I'm using a session variable array of JSON objects to get a list of dynamic data from HTTP url.
this is my component.ts code:
import { IProduct } from "../models/iproduct";
import { Component, OnDestroy, OnInit } from '#angular/core';
import { TimerObservable } from "rxjs/observable/TimerObservable";
import {
Http
} from '#angular/http';
import {
ProcessJsonService
} from '../models/myjsonprocess';
import {
Observable
} from 'rxjs/Rx';
#Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit {
pageTitle: string = 'Process List';
imageWidth: number = 50;
imageMargin: number = 2;
showImage: boolean = false;
listFilter: string = '';
processList: IProduct[] ;
mysessionvariable: IProduct[] ;
errorMessage: string;
private alive: boolean;
private interval: number
constructor(private _processJsonService: ProcessJsonService) {
this.processList = [];
this.mysessionvariable = [];
this.alive = true;
this.interval = 1000;
}
ngOnInit() {
TimerObservable.create(0, this.interval)
.takeWhile(() => this.alive)
.subscribe(() => {
this._processJsonService.getProcesslist()
.subscribe(processList => {
if (processList instanceof Array) {
this.processList = processList;
this.mysessionvariable = this.SaveDataToLocalStorage(processList);
this.processList = this.mysessionvariable;
} else {
this.processList = [processList];
this.mysessionvariable = this.SaveDataToLocalStorage(processList);
this.processList = this.mysessionvariable;
}
});
});
}
ngOnDestroy(){
this.alive = false;
}
SaveDataToLocalStorage(data)
{
var mysessionarray: any[] = Array.of(JSON.parse(localStorage.getItem('session')));
// Parse the serialized data back into an aray of objects
// localStorage.setItem('session', JSON.stringify(data));
// Push the new data (whether it be an object or anything else) onto the array
//console.log("my mysessionarray is", mysessionarray)
console.log("my data in push is", data)
mysessionarray.push(data);
//localStorage.setItem('session', JSON.stringify(mysessionarray));
console.log("my data after push is", mysessionarray)
return mysessionarray;
}
}
This is my service:
import {
Injectable
} from '#angular/core';
import {
Http,
HttpModule,
Headers,
RequestOptions,
Response
} from '#angular/http';
import {
HttpClientModule
} from '#angular/common/http';
import {
Observable
} from 'rxjs/Rx';
import 'rxjs/Rx'; //get everything from Rx
import 'rxjs/add/operator/toPromise';
import {
IProduct
} from "../models/iproduct";
#Injectable()
export class ProcessJsonService {
constructor(private http: Http) {}
//
getProcesslist(): Observable < IProduct[] > {
let url = 'myURL';
return this.http.request(url).map(res => res.json());
}
}
I'm getting this error
ERROR TypeError: mysessionarray.push is not a function
at ProductListComponent.SaveDataToLocalStorage (product-list.component.ts:71)
at SafeSubscriber.eval [as _next] (product-list.component.ts:50)
at SafeSubscriber.__tryOrUnsub (Subscriber.js:240)
at SafeSubscriber.next (Subscriber.js:187)
at Subscriber._next (Subscriber.js:128)
at Subscriber.next (Subscriber.js:92)
at MapSubscriber._next (map.js:85)
at MapSubscriber.Subscriber.next (Subscriber.js:92)
at XMLHttpRequest.onLoad (http.js:1591)
at ZoneDelegate.invokeTask (zone.js:421)
Please any help on getting this fixed? am I missing some imports? or please what's wrong with my code?
Also, how to refresh data in the JSON array means when a new JSON's data are added I need if this row exists in my array just update its data else add a new row?
You are using JSON.parse method to convert your JSON data into Typescript object.
mysessionarray = JSON.parse(localStorage.getItem('session'));
But it will not convert into array directly as your localStorage.getItem('session') may return JSON object as well.
If you are sure that you will get JSON Array only then you can specify
mysessionarray: any[] = Array.of(JSON.parse(localStorage.getItem('session')));
It will vary on data which it receives. Hope it helps !!
Related
EDIT: This doesn't work with the xml2js npm package since I want to do the opposite, convert json to xml, not the other way around.
I have my API using JSON data format but I also have to save the object that I updated in a text file in an XML format, since this other application that we communicate with only accepts XML format.
I have my service
shipment.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import * as x2js from 'xml2js';
import { map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class ShipmentService {
baseUrl = "http://localhost:5000/api/shipments/"
constructor(
private http: HttpClient
) {}
getShipments() {
return this.http.get(this.baseUrl);
}
getShipment(id) {
return this.http.get(this.baseUrl + id);
}
updateShipment(id: number, shipment) {
return this.http.put(this.baseUrl + id, shipment);
}
}
And tracker.component.ts
import { Component, OnInit } from '#angular/core';
import { ShipmentService } from 'src/app/services/shipment.service';
import { NgbModal } from '#ng-bootstrap/ng-bootstrap';
import { ShipmentModalComponent } from '../shipment-modal/shipment-modal.component';
import { Router } from '#angular/router';
import { NgxSpinnerService} from 'ngx-spinner';
var convert = require('xml-js');
#Component({
selector: 'app-tracker',
templateUrl: './tracker.component.html',
styleUrls: ['./tracker.component.css']
})
export class TrackerComponent implements OnInit {
shipments:any = [];
shipment:any = {};
modal_on:boolean = false;
modalcontent:any;
closeResult = '';
reference: string;
constructor(
private shipmentService: ShipmentService,
private modalService: NgbModal,
private spinner: NgxSpinnerService,
private router: Router
) {}
ngOnInit() {
this.getShipments();
}
convertToXML(json) {
var options = {compact: true};
var result = convert.json2xml(json, options);
console.log(result);
}
getShipments() {
this.spinner.show(undefined,{
type: "square-spin",
size: "medium",
bdColor: 'rgba(0,0,0,.5)',
color: "rgb(5, 5, 80)",
fullScreen: false
});
this.shipmentService.getShipments().subscribe(response => {
this.shipments = response;
this.spinner.hide();
this.convertToXML(response);
console.log(response);
}, error => {
console.log(error);
});
}
}
So I tried to use x2js and other xml2json libraries but I had no success converting the JSON object into an XML object or string for that matter.
So I used js2xmlparser npm package and I wrote the following method on my service.ts file and component.ts file as follows:
service.ts
import * as JsonToXML from 'js2xmlparser';
convertXML(obj) {
let options = {
format: {
doubleQuotes: true
},
declaration: {
include: false
}
}
return JsonToXML.parse("UniversalEvent", obj, options);
}
and in my component.ts file i wrote the following method:
openModal(content, shipment) {
// this.modal_on = true;
let new_obj = {};
this.modalcontent = shipment;
this.modalService.open(content, {ariaLabelledBy: 'modal-basic-title'});
new_obj = this.addXmlAttr(new_obj);
this.xmlShipment = this.shipmentService.convertXML(new_obj);
console.log(this.xmlShipment)
console.log(this.modalcontent);
}
addXmlAttr(obj) {
obj = {
"#": {
xmlns: "http://www.cargowise.com/Schema/Universal/2011/11",
version:"1.0"
},
Event: {
DataContext: {
DataTargetCollection: {
DataTarget: {
Type: "ForwardingShipment",
Key: this.modalcontent.vortex_Reference
}
}
},
EventTime: this.modalcontent.actual_Pickup,
EventType: "PCF",
AdditionalFieldsToUpdateCollection: {
AdditionalFieldsToUpdate: {
Type: "ForwardingShipment.DocsAndCartage.JP_PickupCartageCompleted",
Value: this.modalcontent.actual_Pickup
}
}
}
}
return obj;
}
As somebody suggested, I edited the json object to my specifications and then parsed it to XML and the converted object looks like so:
<UniversalEvent xmlns="http://exampleurl.com/Schema/Example/2011/11" version="1.0">
<Event>
<DataContext>
<DataTargetCollection>
<DataTarget>
<Type>ForwardingShipment</Type>
<Key>123456</Key>
</DataTarget>
</DataTargetCollection>
</DataContext>
<EventTime>2019-05-22T00:00:00</EventTime>
<EventType>PCF</EventType>
<AdditionalFieldsToUpdateCollection>
<AdditionalFieldsToUpdate>
<Type>ForwardingShipment.DocsAndCartage.JP_PickupCartageCompleted</Type>
<Value>2019-05-22T00:00:00</Value>
</AdditionalFieldsToUpdate>
</AdditionalFieldsToUpdateCollection>
</Event>
</UniversalEvent>
install npm i js2xmlparser
import * as JsonToXML from "js2xmlparser";
console.log(JsonToXML.parse("person", this.obj));
Here this.obj is your JSON object
Stackblitz Example
I wrote not typical code for case, where I get some information from API server, but don't know, how looks all response fields. After getting response I should create form for update this and sending back.
Because I don't know all ngModels, I generate some fields dynamically after response and assign it to ngModel in cycle in my template.
After stopping my ng serve -o on next first start up my Angular 5 app I get compile error. If I comment problem's code, compile, and after that uncomment it - all works fine.
order.component.ts
import {Component, OnInit} from '#angular/core';
import {UserService} from '../user/user.service';
import {OrderService} from './order.service';
import {enumUserTypes} from '../user/user.model';
import {Router, ActivatedRoute, ParamMap} from '#angular/router';
import 'rxjs/add/operator/switchMap';
import {Order} from './order.model';
import {Observable} from 'rxjs/Observable';
#Component({
selector: 'app-order',
templateUrl: './order.component.html',
styleUrls: ['./order.component.scss']
})
export class OrderComponent implements OnInit {
orderContent = [];
edit: boolean;
userTypes = enumUserTypes;
constructor(
private route: ActivatedRoute,
private router: Router,
public userService: UserService,
public orderService: OrderService
) {
}
ngOnInit() {
this.route.paramMap
.switchMap((params: ParamMap) =>
this.orderService.getOrder(params.get('orderId'))).subscribe(response => {
this.orderService.order = response;
});
this.edit = false;
}
editOrder() {
for (let item in this.orderService.order.orderContent) {
if (this.orderService.order.orderContent.hasOwnProperty(item)) {
let newClassFieldName: string = this.orderService.order.orderContent[item].className;
let newClassFieldLabel: string = this.orderService.order.orderContent[item].label;
let newClassFieldValue: string = this.orderService.order.orderContent[item].value;
this[newClassFieldName] = {
className: newClassFieldName as string,
label: newClassFieldLabel as string,
value: newClassFieldValue as string
};
this.orderContent.push({
className: this[newClassFieldName].className,
label: this[newClassFieldName].label,
value: this[newClassFieldName].value
});
}
}
this.edit = true;
}
submit() {
this.orderContent = [];
for (let item in this) {
if (this.hasOwnProperty(item) &&
item.substring(0, 17) === 'orderContentField') {
this.orderContent.push({
// error TS2339: Property 'className' does not exist on type 'this[keyof this]'.
className: this[item].className,
// error TS2339: Property 'label' does not exist on type 'this[keyof this]'.
label: this[item].label,
// error TS2339: Property 'value' does not exist on type 'this[keyof this]'.
value: this[item].value
});
}
}
this.orderService.order.orderDataUpdate = new Date();
this.orderService.updateOrder(
this.userService.user.userId,
this.orderService.order.orderName,
this.orderService.order.orderCost,
this.orderContent).subscribe(response => {
});
}
saveEditsOrder() {
this.edit = false;
}
}
order.component.html
<div *ngIf="this.edit" class="wrapper--order--edit-form">
<form class="form" #OrderEditPageForm="ngForm" novalidate>
<ng-container *ngFor="let item of this.orderService.order.orderContent">
<label class="label" for="{{item.className}}">{{item.label}}</label>
<input class="input"
[(ngModel)]="this[item.className].value"
id="{{item.className}}"
name="{{item.className}}"/>
</ng-container>
<button class="btn"
type="submit"
role="button"
(click)="submit()">
Send
</button>
</form>
order.service.ts
import {Injectable} from '#angular/core';
import {Order} from './order.model';
import {Router} from '#angular/router';
import {HttpClient} from '#angular/common/http';
import {UserService} from '../user/user.service';
import {Observable} from 'rxjs/Observable';
import {apiRoutes} from '../app.config';
#Injectable()
export class OrderService {
order: Order = new Order();
constructor(private router: Router,
private httpClient: HttpClient,
public userService: UserService) {
}
createOrder(userId: number, orderName: string, orderCost: number, orderContent: any): Observable<Order> {
return this.httpClient.post<Order>(apiRoutes.orders,
{
userId: userId,
orderName: orderName,
orderCost: orderCost,
isOrderOpen: this.order.isOrderOpen,
isOrderPaidOf: this.order.isOrderPaidOf,
orderWorkStatus: this.order.orderWorkStatus,
orderPaymentStatus: this.order.orderPaymentStatus,
orderDataOpened: this.order.orderDataOpened,
orderDataUpdate: this.order.orderDataUpdate,
orderDataClosed: this.order.orderDataClosed,
orderDataPayment: this.order.orderDataPayment,
conversationId: this.order.conversationId,
orderContent: orderContent
});
}
updateOrder(userId: number, orderName: string, orderCost: number, orderContent: any): Observable<Order> {
return this.httpClient.put<Order>(apiRoutes.order + this.order._id,
{
userId: userId,
orderName: orderName,
orderCost: orderCost,
isOrderOpen: this.order.isOrderOpen,
isOrderPaidOf: this.order.isOrderPaidOf,
orderWorkStatus: this.order.orderWorkStatus,
orderPaymentStatus: this.order.orderPaymentStatus,
orderDataOpened: this.order.orderDataOpened,
orderDataUpdate: this.order.orderDataUpdate,
orderDataClosed: this.order.orderDataClosed,
orderDataPayment: this.order.orderDataPayment,
conversationId: this.order.conversationId,
orderContent: orderContent
});
}
getUserOrders(): Observable<Order> {
return this.httpClient.post<Order>(apiRoutes.userOrders, {userEmail: this.userService.user.userEmail});
}
getOrder(id: string): Observable<Order> {
return this.httpClient.get<Order>(apiRoutes.order + id);
}
}
order.model.ts
export class Order {
constructor(
public _id: number = null,
public userId: number = null,
public orderName: string = '',
public orderCost: number = null,
public isOrderOpen: boolean = true,
public isOrderPaidOf: boolean = false,
public orderWorkStatus: string = 'Checking documents',
public orderPaymentStatus: string = 'Not paid',
public orderDataOpened: Date = new Date(),
public orderDataUpdate: Date = null,
public orderDataClosed: Date = null,
public orderDataPayment: Date = null,
public conversationId: number = null,
public orderContent: Object = []
) {
}
}
I get some error on new fields creating after getting response API.
Errors TS2339: Property 'className' does not exist on type 'this[keyof this]'.
Error TS2339: Property 'label' does not exist on type 'this[keyof this]'.
Error TS2339: Property 'value' does not exist on type 'this[keyof this]'.
How can I solve this?
I should something switch off this checking in compiler or reformat my code?
This is your error :
editOrder() {
/* ... */
this.orderContent.push({
className: this[newClassFieldName].className,
label: this[newClassFieldName].label,
value: this[newClassFieldName].value
});
}
More precisely :
this[newClassFieldName].className
When you write that, you try to read a variable in your OrderComponent.
This could have worked, because you declare that variable just before. But your issue is that you created variables into that variable, that have very strange names. The error tells you that :
Property 'className' does not exist on type 'this[keyof this]'
You declare the variable like this
let newClassFieldName: string = this.orderService.order.orderContent[item].className;
Just before that, could you write
console.log(this.orderService.order.orderContent[item].className);
And tell me the result ?
I am stuck at the phase of learning CRUD operation in Angular 5
I have been trying for hours but no avail, it seems i can't solve the error.
When I subscribe data which comes from service and try to insert data using push. It says undefined.
addtasks.component.ts
import { Component } from '#angular/core';
import { AddTaskService } from '../../services/add-task.service';
import { Tasks } from '../../../Tasks/Tasks';
#Component({
selector: 'app-addtasks',
templateUrl: './addtasks.component.html',
styleUrls: ['./addtasks.component.css']
})
export class AddtasksComponent {
tasks: Tasks[];
title: string;
constructor(private addTaskService: AddTaskService) {
console.log("Add tasks page has been accessed...");
}
addTasks(event){
event.preventDefault();
var newTask = {
title: this.title,
isDone: false
};
this.addTaskService.addTask(newTask).subscribe(task => {
this.tasks.push(task);
this.title = '';
});
}
}
add-task.service.ts
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class AddTaskService {
constructor(private http: Http) { console.log("Add Task service initialized..."); }
addTask(newTask){
var headers = new Headers();
headers.append('Content-Type', 'application/json');
console.log(newTask);
return this.http.post('http://localhost:2200/api/tasks', JSON.stringify(newTask), {headers: headers})
.map(res => res.json());
}
}
Model
Tasks.ts
export class Tasks {
title: string;
isDone: boolean;
}
The error showing in my console
TypeError columnNumber: 13 fileName:
"http://localhost:2200/main.bundle.js" lineNumber: 193 message:
"_this.tasks is undefined" stack:
"../../../../../src/app/components/addtasks/addtasks.component.ts/AddtasksComponent.prototype.addTasks/<#http://localhost:2200/main.bundle.js:193:13\n../../../../rxjs/_esm5/Subscriber.js/SafeSubscriber.prototype.tryOrUnsub#http://localhost:2200/vendor.bundle.js:1697:13\n../../../../rxjs/_esm5/Subscriber.js/SafeSubscriber.prototype.next#http://localhost:2200/vendor.bundle.js:1644:17\n../../../../rxjs/_esm5/Subscriber.js/Subscriber.prototype._next#http://localhost:2200/vendor.bundle.js:1585:9\n../../../../rxjs/_esm5/Subscriber.js/Subscriber.prototype.next#http://localhost:2200/vendor.bundle.js:1549:13\n../../../../rxjs/_esm5/operators/map.js/MapSubscriber.prototype._next#http://localhost:2200/vendor.bundle.js:4978:9\n../../../../rxjs/_esm5/Subscriber.js/Subscriber.prototype.next#http://localhost:2200/vendor.bundle.js:1549:13\nonLoad#http://localhost:2200/vendor.bundle.js:75626:21\n../../../../zone.js/dist/zone.js/http://localhost:2200/polyfills.bundle.js:2504:17\nonInvokeTask#http://localhost:2200/vendor.bundle.js:53623:24\n../../../../zone.js/dist/zone.js/http://localhost:2200/polyfills.bundle.js:2503:17\n../../../../zone.js/dist/zone.js/http://localhost:2200/polyfills.bundle.js:2271:28\n../../../../zone.js/dist/zone.js/http://localhost:2200/polyfills.bundle.js:2578:24\ninvokeTask#http://localhost:2200/polyfills.bundle.js:3619:9\nglobalZoneAwareCallback#http://localhost:2200/polyfills.bundle.js:3645:17\n"
__proto: Object { stack: "", … }
You should initialize tasks variable before using it.
Initialize it in the constructor function.
constructor(private addTaskService: AddTaskService) {
console.log("Add tasks page has been accessed...");
this.tasks = [];
}
That's why you have an error saying its undefined.
I encounter a strange problem with my custom class in angular2 after passing it through an Observable chain.
I always receive the error:
EXCEPTION: f.mapToParams is not a function
ORIGINAL STACKTRACE:
TypeError: f.mapToParams is not a function
at SafeSubscriber._next (filter.component.ts)
...
Uncaught TypeError: f.mapToParams is not a function
at Safesubscriber._next (filter.component.ts)
Here is my coding:
filter.ts:
import { Params } from '#angular/router';
export class Filter {
public text:String = '';
public mapToParams():Params {
let params:Params = {};
// Do some mapping here...
return params;
}
}
filter.component.ts
import { Component, OnInit Output, EventEmitter } from '#angular/core';
import { Router, Params } from '#angular/router';
import { Filter } from './filter';
import { Observable, Subject } from 'rxjs/Rx';
export class FilterComponent implements OnInit {
private _filter:Filter;
private _filterStream = new Subject<Filter>();
ngOnInit() {
this._filter = new Filter();
this._filterStream
.debounceTime(300)
.switchMap((f:Filter) => Observable.of(f))
.subscribe((f:Filter) => {
let params:Params = {};
console.log(f.text); // <-- No problem here
// params = this._map(f); // <-- This would work
params = f.mapToParams(); // <-- Here occurs the error
});
}
private _map(f:Filter):Params {
// Do some mapping here
}
public onInputChanged(searchText:String):void {
this._mergeFilter( {
map(f:Filter) {
f.text = searchText;
}
})
}
private _mergeFilter(callback:FilterMergeCallback):void {
let f:Filter = JSON.parse(JSON.stringify(this._filter));
callback.map(f);
this._filterStream.next(f);
}
}
I have tried to comment out the debounceTime and switchMap statement but with no success.
At a different point in my coding the filter.mapToParams method can be called without any problems. It seems to me like the Observable chain strips all methods from my object.
Here is my angular config:
#angular/cli: 1.0.0.-beta.32.3
#angular/common: ^2.4.0
#angular/compiler ^2.4.0
#angular/core ^2.4.0
rxjs: ^5.1.0
Can anyone help me on this?
I think I got it:
I copied the current _filter Object to a new filter variable by
JSON.parse(JSON.stringify())
By this, all methods get stripped from the new object.
Means, I have to find a new method to clone the object...
Thanks all for you replies!
This question already has answers here:
How to return value from an asynchronous callback function? [duplicate]
(3 answers)
Closed 6 years ago.
Im having trouble merging 3 objects array. My objective is to merge 3 arrays to one and send HTTP POST to the server.
I have tried using concat but Im getting this error:
EXCEPTION: Error in ./PreviewEmailPage class PreviewEmailPage_Host - inline template:0:0 caused by: Cannot read property 'concat' of undefined
These are my codes:
import { Component } from '#angular/core';
import { NavParams, NavController, LoadingController } from 'ionic-angular';
import { Validators, FormGroup, FormControl } from '#angular/forms';
import { Http, Headers} from '#angular/http';
import 'rxjs/add/operator/map';
import { Storage } from '#ionic/storage';
#Component({
selector: 'preview-email-page',
templateUrl: 'preview-email.html',
})
export class PreviewEmailPage {
headers: Headers;
loading: any;
url: string;
preview: any[];
FirstArray: any[];
SecondArray: any[];
ThirdArray: any[];
PostData: any[];
constructor(
public nav: NavController,
public navParams: NavParams,
public loadingCtrl: LoadingController,
public localStorage: Storage,
public http: Http,
) {
this.localStorage.get('FirstArray').then((value) => {
this.FirstArray= value;
})
this.localStorage.get('SecondArray').then((value) => {
this.SecondArray= value;
})
this.localStorage.get('ThirdArray').then((value) => {
this.ThirdArray= value;
})
this.PostData = this.FirstArray.concat(this.SecondArray);
this.PostData = this.PostData.concat(this.ThirdArray);
this.loading = this.loadingCtrl.create();
}
ionViewWillEnter(){
this.headers = new Headers();
this.headers.append("Content-Type", "application/x-www-form-urlencoded");
console.log(this.PostData);
this.getPreview();
}
getPreview(){
this.loading.present();
this.url = 'https://domain.com/REST/getpreview.php';
this.http.post(this.url, this.PostData, {headers: this.headers}).map(res => res.json()).subscribe(res => {
console.log(res);
this.preview = res;
}, err => {
console.log('error');
})
}
}
Since this.localStorage.get is an async operation your this.FirstArray is not defined untill the then is executed.
What you can do is run them all in parallel with Promise.all:
Promise.all([this.localStorage.get('FirstArray'), this.localStorage.get('SecondArray'), this.localStorage.get('ThirdArray')]).then(values => {
this.FirstArray= values[0];
this.SecondArray= values[1];
this.ThirdArray= values[2];
this.PostData = this.FirstArray.concat(this.SecondArray);
this.PostData = this.PostData.concat(this.ThirdArray);
});