Angular Trouble Emptying Array - json

Hell, I have an e-commerce application in which I am trying to empty the shopping cart after payment is successful, no matter what I have tried the array will not empty. I have tried cartItems.length = 0,
cartItems = [] as well as splice. I must be missing something. Code snippet below I will walk you through it.
This is my Model
import { Product } from './product';
export class CartItem {
id: number;
productId: number;
productName: string;
qty: number;
price: number;
size:string;
imageUrl:string;
constructor(id:number, size:string,
product:Product, qty= 1) {
this.id = id;
this.productId = product.id;
this.price = product.price;
this.size = size;
this.productName = product.name;
this.qty = qty;
this.imageUrl = product.imageUrl;
}
}
This is my car service as you can see I remove and add to cart as well as get cart items, there is no problem here. The remove and add are button clicks on html
export class CartService {
product: any;
cartItem: CartItem[] = [];
cartUrl = 'http://localhost:4000/cart';
constructor(private http: HttpClient, private router: Router,
private route: ActivatedRoute) {
}
getCartItems(): Observable<CartItem[]> {
return this.http.get<CartItem[]>(cartUrl).pipe(
map((result: any[]) => {
let cartItems: CartItem[] =[];
for(let item of result) {
cartItems.push( new CartItem(item.id, item.size,
item.product, item.imageUrl ));
}
return cartItems;
})
);
}
addProductToCart(product:Product):Observable<any>{
return this.http.post(cartUrl, {product});
}
RemoveProductFromCart(id:number):Observable<void>{
//this.cartItems.splice(index,1)
alert("show deleted item");
return this.http.delete<CartItem[]>(`${this.cartUrl}/${id}`)
.pipe(catchError(_err => of (null))
);
}
buttonClick() {
const currentUrl = this.router.url;
this.router.navigateByUrl('/', {skipLocationChange:
true}).then(() => {
this.router.navigate([currentUrl]);
});
//alert("Should Reload");
}
addPurseToCart(product:Product):Observable<any>{
return this.http.post(cartUrl, {product})
}
}
Here is the checkout component, I injected the cart component so I could call the the empty cart function which resides in the cart component. I did import the CartComponent. Check out is based on cart. When the cart is emptied so should checkout
#Component({
providers:[CartComponent], //injected CartComponent
selector: 'app-checkout',
templateUrl: './checkout.component.html',
styleUrls: ['./checkout.component.scss']
})
export class CheckoutComponent implements OnInit {
// #ViewChild(CartComponent) // #ViewChild(CartItemComponent) cartitemComponent: CartItemComponent
cartComponent: CartComponent
#Input() product: CartItem;
#Input() cartItem: CartItem;
cartUrl = 'http://localhost:4000/cart';
size;
cartItems = [];
cartTotal = 0;
itemTotal = 0;
shipping = 8.00;
estimatedTax = 0;
myValue: any;
constructor(private msg: MessengerService, private route:
ActivatedRoute,
private router: Router, private
cartService:CartService,
private productService: ProductService, private
comp:CartComponent) {}
ngOnInit() {
this.loadCartItems();
}
}
loadCartItems(){
this.cartService.getCartItems().subscribe((items:
CartItem[]) => {
this.cartItems = items;
this.calcCartTotal();
this.calNumberOfItems();
})
}
calcCartTotal() {
this.cartTotal = 0;
this.cartItems.forEach(item => {
this.cartTotal += (item.qty * item.price);
})
this.cartTotal += this.shipping;
this.myValue = this.cartTotal
render(
{
id:"#paypal-button-container",
currency: "USD",
value: this.myValue,
onApprove: (details) =>{
alert("Transaction Suceessfull")
console.log(this.myValue);
this.comp.handleEmptyCart();
}
}
);
}
calNumberOfItems(){
console.log("Trying to get tolal items")
this.itemTotal = 0;
this.cartItems.forEach(item => {
this.itemTotal += item.qty;
})
}
}
cart component
export class CartComponent implements OnInit {
#Input() product: CartItem;
#Input() cartItem: CartItem;
//items: CartItem [] =[];
cartUrl = 'http://localhost:4000/cart';
val;
size;
cartItems = [];
cartTotal = 0
itemTotal = 0
constructor(private msg: MessengerService, private
cartService:CartService, private productService:
ProductService, private formBuilder:FormBuilder, private
_data:AppserviceService, private router:Router) { }
ngOnInit(): void {
this.handleSubscription();
this.loadCartItems();
}
handleSubscription(){
this.msg.getMsg().subscribe((product: Product) => {
})
}
loadCartItems(){
this.cartService.getCartItems().subscribe((items:
CartItem[]) => {
this.cartItems = items;
console.log("what is in cartItems" + this.cartItems)
console.log("What does this property hold" +
this.cartItem)
this.calcCartTotal();
this.calNumberOfItems();
})
}
calcCartTotal() {
this.cartTotal = 0
this.cartItems.forEach(item => {
this.cartTotal += (item.qty * item.price)
})
}
calNumberOfItems(){
console.log("Trying to get tolal items")
this.itemTotal = 0
this.cartItems.forEach(item => {
this.itemTotal += item.qty
})
}
handleEmptyCart(){
alert("Hit Empty Cart");
/*here I get the cart items to see what is in the array
and try to empty, it does show tow objects in the
array*/
this.cartService.getCartItems().subscribe((items:
CartItem[]) => {
this.cartItems = items;
this.cartItems.length=0
// this.cartItems = [];
console.log("what is in cartItems" + this.cartItems)
})
}
}
I have used different approaches trying to empty the cart nothing works. It makes me think I'm stepping on something or somehow creating events calling the loadCartItems to many times not sure but according to my research one of these approaches should work. If someone can please help me out I'm stuck. I would greatly appreciate it.

Short answer: run change detection ChangeDetectorRef.detectChanges()
Long answer:
You need to understand how angular works.
Lets assume simple example:
<div id="val">{{val}}</div><button (click)="val++">Increase<div>
So when u click button variable changes, but who changes actual #val div content? Answer is that Angular uses zone.js to patch/change a lot of functions to run Angular change detection after most of JS events (you can control type of this events to include/exclude some of them). Also Promise is patched same way, thats why after some Promise is resolve change detection is run.
However, here you run some render method with onApprove callback which is probably some 3rd party library (?) and zone.js is not aware of it (https://angular.io/guide/zone#ngzone-run-and-runoutsideofangular). And though running detectChanges gonna help u, u better re-write your code, so onApprove is always in Angular zone and u never gonna face similar bugs in future when using this method.

Related

I cant add the Input Decorator in Angular

I'm getting data from father component with Input in Angular, but it doen't work
My child:
export class ForumComponent implements OnInit {
#Input() id_foro: number = 3;
nombre: string = '';
desc: string = ''
forum = this.forumService.getById(this.id_foro).subscribe((data: Forum[]) => {
this.nombre = data[0].name
this.desc = data[0].description
});
constructor(private forumService: ForumService) { }
where I call it:
<div *ngIf="forum.id_category_fk === category.id">
<app-forum [id_foro]="forum.id"></app-forum>
</div>
That is not the correct way to call the method and assign the value.
For your scenario, you should call the service method in ngOnInit().
export class ForumComponent implements OnInit {
#Input() id_foro: number = 3;
...
forum: Forum;
...
ngOnInit() {
this.forumService.getById(this.id_foro).subscribe((data: Forum[]) => {
this.nombre = data[0].name;
this.desc = data[0].description;
this.forum = data[0];
});
}
}

Type error Cannot find properties of undefined (reading id)

I'm at a lost here. I have a couple of services, one has been working for month and the newer one for some weeks, then all of a sudden a couple of days ago I start to get two console errors "Cannot read properties of undefined(reading id). I have not changed anything.
If I can fix one then I can understand the other because they both have the same error. When I did my research it talks about initializing.
This is an e-commerce site, when the user clicks on the heart it gets added to wishlistitems in my json file. The user should have the ability to go to favorites and it shows all of the wishlist items. As I stated it was working now I get errors. I have a two models(class) I have two components wishlist-list and wishlistitems the html will display the url for the images and I have a serive.
Here is the wish Model
import { Product } from './product';
export class Wish {
id:number;
productId: number;
productName: string;
description: string;
qty:number;
price: number;
imageUrl: string;
constructor(id:number, product:Product, qty=1, ){
this.id = id;
this.productId = product.id;
this.price = product.price;
this.productName = product.name;
this.qty = qty;
this.imageUrl = product.imageUrl;
this.description = product.description;
}
}
Here is the Product Model
export class Product {
id:number;
name: string;
description: string;
price: number;
imageUrl: string;
constructor(id:number, name, description="", price=0, imageUrl="" ){
this.id=id
this.name = name
this.description = description
this.price= price
this.imageUrl = imageUrl
}
}
Here is my Wishlist component
import { Component, OnInit, Input } from '#angular/core';
import {ProductService} from 'src/app/services/product.service'
import { MessengerService } from 'src/app/services/messenger.service';
import { WishlistService } from 'src/app/services/wishlist.service';
import { WishlistItemService } from '#app/services/wishlist-item.service';
import { Wish} from 'src/app/models/wish';
import {Product} from 'src/app/models/product';
#Component({
selector: 'app-wishlist-list',
templateUrl: './wishlist-list.component.html',
styleUrls: ['./wishlist-list.component.scss']
})
export class WishlistListComponent implements OnInit {
#Input() product: any;
productList: Product[]= [];
wishitemList: Wish[]= [];
wishItems = [];
constructor( private msg: MessengerService, private productService: ProductService,
private wishlistService: WishlistService,
private _wishlistitemService: WishlistItemService ) { }
ngOnInit(): void {
this.loadwishlistList()
}
loadwishlistList(){
alert("Loading wish list item");
this._wishlistitemService.getWishlistitem().subscribe((items: Wish[]) => {
console.log("A wish List Item" + items);
this.wishItems=items;
})
}
}
Here is my service
#Injectable({
providedIn: 'root'
})
export class WishlistItemService {
product:any;
id:number;
wishlistitemUrl = 'http://localhost:3000/wishlistitem'; //I have this in a api file
constructor(private http: HttpClient) { }
getWishlistitem(): Observable<Wish[]>{
return this.http.get<Wish[]>(wishlistitemUrl).pipe(
map((result: any[]) => {
let wishItems: Wish[] =[];
for(let item of result) {
let productExists = false
for(let i in wishItems){
if(wishItems[i].productId === item.product.id){ //this is line I get error on
wishItems[i].qty++
productExists = true
break;
}
}
if (!productExists){
wishItems.push(new Wish(item.id,item.product, item.name));
}
}
return wishItems;
})
);
}
}
I am at a lost here for it to work then stop working. I'm pulling my hair out, I tried making adjustments but nothing work. I read something about initializing, I'm in need of help.
Thanking You Advance
PH

How to get a directive to react to an EventEmitter in a component

I have a CustomComponent which emits a value (let's just call it "error") if a http request to the back end api returns an error. How can I get a directive (call it Form Directive), applied to this form, to recognize when the "error" value is emitted by CustomComponent?
Code for CustomComponent:
export class CustomComponent extends FormComponent<Custom> {
constructor(
protected fb: FormBuilder,
private httpService: HttpService) {
super(fb);
}
currentVal: string = '';
inputType: string = 'password';
showPasswordTitle: string = 'Show Password';
showPasswordStatus: boolean = false;
form: FormGroup;
#Output() invalidOnError = new EventEmitter<string>();
protected buildForm(): FormGroup {
return this.form = this.fb.group({
fieldA: ['', Validators.required],
fieldB: ['', Validators.required],
fieldC: [''],
fieldD: ['', [Validators.required, Validators.pattern('[0-9]{10}')]]
}
protected doSubmit(): Observable<Custom> {
return this.httpService.callDatabase<Custom>('post', '/api/users/custom', this.value);
};
protected get value(): Registration {
return {
fieldA: this.fieldA.value,
fieldB: this.fieldB.value,
fieldC: this.fieldC.value,
fieldD: this.fieldD.value
};
}
get fieldA() { return this.form.get('fieldA'); }
get fieldB() { return this.form.get('fieldB'); }
get fieldC() { return this.form.get('fieldC'); }
get fieldD() { return this.form.get('fieldD'); }
protected onError() {
if (this.error.length) {//error.length indicates some of the fields in the form are already registered in the database
Object.keys(this.error).forEach(element => {
let formControl = this.form.get(this.error[element])
this.currentVal = formControl.value;
formControl.setValidators(formControl.validator ? [formControl.validator, unique(this.currentVal)] : unique(this.currentVal))
formControl.updateValueAndValidity()
this.invalidOnError.emit('error');
})
}
}
Code for FormComponent:
export abstract class FormComponent<T> implements OnInit {
protected form: FormGroup = null;
submitted = false;
completed = false;
error: string = null;
constructor(protected fb: FormBuilder) {}
ngOnInit() {
this.form = this.buildForm();
}
onSubmit() {
this.submitted = true;
if (this.form.valid) {
this.doSubmit().subscribe(
() => {
this.error = null;
this.onSuccess();
},
err => {
this.error = err
this.onError();
},
() => {
this.submitted = false;
this.completed = true;
}
)
}
}
protected abstract get value(): T;
protected abstract buildForm(): FormGroup;
protected abstract doSubmit(): Observable<T>;
protected onSuccess() {}
protected onError() {}
}
Code for Form Directive (works well when user clicks Submit button, which triggers onSubmit event in CustomComponent):
#Directive({
selector: 'form'
})
export class FormSubmitDirective {
submit$ = fromEvent(this.element, 'submit').pipe(shareReplay(1));
constructor(private host: ElementRef<HTMLFormElement>) {}
get element() {
return this.host.nativeElement;
}
}
I was hoping something like this could be the solution to my question, but this for sure doesn't work.
invalidOnError$ = fromEvent(this.element, 'error').pipe(shareReplay(1));
The idea is to use submit$ or invalidOnError$ from the directive to focus on the first invalid field in the form. Works fine for submit$, but not invalidOnError$. Appreciate some help - still fairly new to Angular.
I got this to work in a round about manner, by using the #Input decorator in another form directive which also imports submit$ from Form Directive.
No changes to code for FormComponent and Form Directive vs. what's shown in the question.
Relevant code from Custom component:
export class CustomComponent extends FormComponent<Custom> {
invalidOnError: string = '';
form: FormGroup;
protected buildForm(): FormGroup {
return this.form = this.fb.group({
fieldA: ['', Validators.required],
fieldB: ['', Validators.required],
fieldC: [''],
fieldD: ['', [Validators.required, Validators.pattern('[0-9]{10}')]]
}
protected doSubmit(): Observable<Custom> {
invalidOnError = '';
return this.httpService.callDatabase<Custom>('post', '/api/users/custom', this.value);
};
protected get value(): Registration {
return {
fieldA: this.fieldA.value,
fieldB: this.fieldB.value,
fieldC: this.fieldC.value,
fieldD: this.fieldD.value
};
}
get fieldA() { return this.form.get('fieldA'); }
get fieldB() { return this.form.get('fieldB'); }
get fieldC() { return this.form.get('fieldC'); }
get fieldD() { return this.form.get('fieldD'); }
protected onError() {
if (this.error.length) {//error.length indicates some of the fields in the form are already registered in the database
invalidOnError = 'invalid'
Object.keys(this.error).forEach(element => {
let formControl = this.form.get(this.error[element])
this.currentVal = formControl.value;
formControl.setValidators(formControl.validator ? [formControl.validator, unique(this.currentVal)] : unique(this.currentVal))
formControl.updateValueAndValidity()
this.invalidOnError.emit('error');
})
}
}
Relevant code from CustomComponentTemplate:
<form class="bg-light border" appFocus="FieldA" [formGroup]="CustomForm"
[invalidOnError]="invalidOnError" (ngSubmit)="onSubmit()">
Relevant code from invalidFormControlDirective (imports submit$ from Form Directive):
#Directive({
selector: 'form[formGroup]'
})
export class FormInvalidControlDirective {
private form: FormGroup;
private submit$: Observable<Event>;
#Input() invalidOnError: string = ''; //this is the #Input variable invalidOnError
constructor(
#Host() private formSubmit: FormDirective,
#Host() private formGroup: FormGroupDirective,
#Self() private el: ElementRef<HTMLFormElement>
) {
this.submit$ = this.formSubmit.submit$;
}
ngOnInit() {
this.form = this.formGroup.form;
this.submit$.pipe(untilDestroyed(this)).subscribe(() => {
if (this.form.invalid) {
const invalidName = this.findInvalidControlsRecursive(this.form)[0];
this.getFormElementByControlName(invalidName).focus();
}
});
}
ngOnChanges(){
of(this.invalidOnError).pipe(filter(val => val == 'invalid')).subscribe(() => {
if (this.form.invalid) {
const invalidName = this.findInvalidControlsRecursive(this.form)[0];
this.getFormElementByControlName(invalidName).focus();
}
});
}
ngOnDestroy() { }
// findInvalidControlsRecursive and getFormElementByControlName defined functions to get invalid controls references
}
That said, I'd be interested in 1) somehow bringing code under onChanges lifecyle into ngOnInit lifecyle in invalidFormControlDirective (couldn't get that to work), and 2) find out if there is some way to emitting an event and processing it with Rxjs fromEventPattern as opposed to passing the #Input variable invalidOnError into invalidFormControlDirective.

Angular 6 : Not able to fetch individual data from different component's JSON object

Scenario:
In Component1, I have a table, I am sending single row's data as a JSON object to Component2's object
Expected result:
I should be able to fetch data using object2, eg. object2.id = id1, object2.title = title1
Actual result: I am getting undefined for values in object2, object2.id= undefined , object2.title = undefined
What I tried:
In Component1 I used JSON.stringify(obj) and in Component2 I was using JSON.parse(obj) to get the object values, but I was getting [obj obj] on alert the JSON object.
I got confused as to how did JSON automatically got converted to Obj without using any JSON.parse.
Good news is, data is being passed to object2, when I alert object2 I get the whole object string with all values.
but when I try to populate single value it gives me undefined msg inspite of the values being present
Any idea how else i can check why it is not working ?
Not sure what exactly I am missing, I am searching since past couple of days, did not find any solution on this or any other site.
Any help is appreciated. Thanks.
Here is my code:
Component1
#Component({
selector: 'myjds',
templateUrl: './myjds.component.html',
styleUrls: ['./myjds.component.scss'],
providers: [DatePipe]
})
#NgModule({
imports: [
ThemeModule,
NgxEchartsModule, Ng2SmartTableModule,
NgxChartsModule, ChartModule, NgxSpinnerModule
],
declarations: [
DashboardComponent,
StatusCardComponent,
ContactsComponent,
EchartsPieComponent,
EchartsBarComponent,
],
entryComponents: []
})
export class MyjdsComponent implements OnInit {
config: ToasterConfig;
private message = null;
position = 'toast-top-right';
animationType = 'flyLeft';
title = 'Result';
content = `I'm cool toaster!`;
timeout = 5000;
toastsLimit = 5;
type = 'info';
isNewestOnTop = true;
isHideOnClick = true;
isDuplicatesPrevented = false;
isCloseButton = true;
EntityID;
LoginUserId;
jdData: JobDescription[] = [];
indJobDescription = {} as JobDescription;
source: LocalDataSource = new LocalDataSource();
serachResults = [];
public nijobmobile;
public nijobcontactemail;
constructor(
private ServiceObj: ApiService,
private spinner: NgxSpinnerService,
private modalService: NgbModal,
private toasterService: ToasterService,
private activeModal: NgbActiveModal,
private datePipe: DatePipe) {
this.EntityID = localStorage.getItem("Entity");
this.LoginUserId = localStorage.getItem("LoginID");
}
private showToast(type: string, title: string, body: string) {
this.config = new ToasterConfig({
positionClass: this.position,
timeout: this.timeout,
newestOnTop: this.isNewestOnTop,
tapToDismiss: this.isHideOnClick,
preventDuplicates: this.isDuplicatesPrevented,
animation: this.animationType,
limit: this.toastsLimit,
});
const toast: Toast = {
type: type,
title: title,
body: body,
timeout: this.timeout,
showCloseButton: this.isCloseButton,
bodyOutputType: BodyOutputType.TrustedHtml,
};
this.toasterService.popAsync(toast);
}
ngOnInit() {
this.loadJobDescription();
}
loadJobDescription(jdData?) {
if (jdData == null || jdData == undefined || jdData == 0) {
alert("data null e ");
this.spinner.show();
let body = JSON.stringify({
nispname: "nijobdescriptionsearch_sp",
ptype: "alljobdescription",
pnijobdescriptionid: 0,
pniuserid: Number(this.LoginUserId),
pnicompid: this.EntityID
});
alert("body string value : " + body);
this.ServiceObj.apicall(body).subscribe(
res => {
this.spinner.hide();
let data: any = res;
if (data.results.Table.length > 0) {
alert("table returns values:" + data.results.Table.length);
this.jdData = data.results.Table;
localStorage.setItem('Message', JSON.stringify(this.jdData));
this.source.load(this.jdData);
}
},
(err) => {
this.spinner.hide();
}
);
}
else {
alert("data ahe baba");
let loginUserId = localStorage.getItem("LoginID");
alert("loginUserId: " + loginUserId);
this.spinner.show();
let body = JSON.stringify({
nispname: "nijobdescriptionsearch_sp",
ptype: "individualJD",
pnijobdescriptionid: jdData.nijobdescriptionid,
pniuserid: Number(this.LoginUserId),
pnicompid: this.EntityID
});
alert("body stringify:" + body);
this.ServiceObj.apicall(body).subscribe(
res => {
this.spinner.hide();
let data: any = res;
if (data.results.Table.length > 0) {
alert("data length" + data.results.Table.length);
this.indJobDescription = data.results.Table;
localStorage.setItem('Message1', JSON.stringify(this.indJobDescription));
// alert("result of indjobdescription: " + JSON.stringify(this.indJobDescription));
const activeModal = this.modalService.open(IndJobDescriptionComponent, {
size: 'lg',
backdrop: 'static',
container: 'nb-layout',
});
}
},
(err) => {
this.spinner.hide();
}
);
}
}
}
Component2
selector: 'commentresult',
templateUrl: './indjobdescription.component.html',
styleUrls: ['./indjobdescription.component.scss']
})
export class IndJobDescriptionComponent implements OnInit {
private msg: string = '';
private msg1: string = "";
public dialog: any;
public dialog1 :any;
public existingstaffid = [];
errorMsgRolename: string = '';
errorMsgRoledescription: string = '';
isValidRolename: boolean = true;
isValidRoledescription: boolean = true;
public ShlocationAutoComplete;
public ShroleAutoComplete;
public ShskillAutoComplete;
public ShdomainAutoComplete;
public ShcertAutocomplete;
public alldata;
public nijobmobile;
public nijobcontactemail;
pager: any = {};
pagedItems: any[];
jdData: JobDescription[] = [];
indJobDescription = {} as JobDescription;
LoginUserId = localStorage.getItem("LoginID");
source: LocalDataSource = new LocalDataSource();
constructor(private modalService: NgbModal,
private spinner: NgxSpinnerService,
private _sanitizer: DomSanitizer,
private data: DataService,
private activeModal: NgbActiveModal,
private ServiceObj: ApiService,
private pagerService: PagerService,
private toasterService: ToasterService) {
this.EntityID = localStorage.getItem("Entity");
}
profile: any;
private EntityID: string;
private message = null;
config: ToasterConfig;
position = 'toast-top-right';
animationType = 'flyLeft';
title = 'Result';
content = `I'm cool toaster!`;
timeout = 5000;
toastsLimit = 5;
type = 'info';
isNewestOnTop = true;
isHideOnClick = true;
isDuplicatesPrevented = false;
isCloseButton = true;
ngOnInit() {
this.msg1 = localStorage.getItem("Message1");
//this.indJobDescription = JSON.parse(this.msg1); //on doing alert, this line is returning [obj obj]
alert("user id: " + this.indJobDescription.nijobcreateuserid);
}
closeModal() {
this.activeModal.close();
}
private showToast(type: string, title: string, body: string) {
this.config = new ToasterConfig({
positionClass: this.position,
timeout: this.timeout,
newestOnTop: this.isNewestOnTop,
tapToDismiss: this.isHideOnClick,
preventDuplicates: this.isDuplicatesPrevented,
animation: this.animationType,
limit: this.toastsLimit,
});
const toast: Toast = {
type: type,
title: title,
body: body,
timeout: this.timeout,
showCloseButton: this.isCloseButton,
bodyOutputType: BodyOutputType.TrustedHtml,
};
this.toasterService.popAsync(toast);
}
SaveData() {
let t = window.location.host;
let tvpselectiondtl: tvp_selectiondtl[] = [];
let LoginUserId = localStorage.getItem("LoginID");
}
}
PFB screenshot of the JSON string, sorry console.log is not working so had to take screen shot of the alert,
As I can see in json you are storing an array of objects .
this.msg1 = localStorage.getItem("Message1");
this.indJobDescription = JSON.parse(this.msg1); //on doing alert, this line is
returning [obj obj]
alert("user id: " + this.indJobDescription[0].nijobcreateuserid); //It is array
If there is multiple entry of indJobDescription then use *ngFor to read each object.
for (let i = 0; i < this.indJobDescription.length ; i++) {
var jobCreateUserId= this.indJobDescription[i].nijobcreateuserid;
..........
}
and it will solve your issue.
keep this simple
var product=[{"sno":"1","description":"test"}] =Array of object ==>product[0].sno
var product={"sno":"1","description":"test"} = it presents object. ==> product.sno
There are two main ways to share data between components, input and output properties and shared services.
If component 2 is a child of component 1 then use inputs
<component2 [data]="propertyOfComponent1"></component2>
and in component 2 decorate the data property as an input
#Input() data;
After the component has initalised data will be the data passed from component 1. You can access it in the ngOnInit method but not the constructor as it wont be wired up just yet.
If they are not in a parent child relationship use a shared service that is dependency injected into both components constructor.
constructor(private sharedService: SharedService) {
}
and both components will get the same instance of the service.
#Injectable()
export class SharedService {
data = new SomeObject();
}

Pagination - How to wait till dataSource is ready/available

I have a pagination service and component which is working fine except that the dataSource is empty when loading the page first time. By second time, the dataSource is ready and I can display the dataTable and paginate.
Is there any fix to work around this issue, so that the function is invoked after the data is ready/loaded?
setTimeOut() would not be an option based on my tries.
list-user.service.ts:
let registeredUser:USers[] = [];
#Injectable()
export class ListUserService {
constructor(public loginService:LoginService){}
getUserDatasource(page:number, limit:number, sortBy?:string, sortType?:DatatableSortType): IPaginableUsers {
this.loginService.getUsersList().subscribe(
(res) => {
registeredUser = res.message
return registeredUser;
}, (err) => {})
}
...
...
}
list-users.component.ts:
export class ListUsersComponent implements AfterViewInit, OnDestroy {
...
...
constructor( private listUserService:ListUserService, private changeDetectorRef:ChangeDetectorRef) {
this.fetchUserDataSource();
}
ngOnInit(){}
ngAfterViewInit() {
if (this.datatable) {
Observable.from(this.datatable.selectionChange).takeUntil(this.unmount$).subscribe((e:IDatatableSelectionEvent) =>
this.currentSelection$.next(e.selectedValues)
);
Observable.from(this.datatable.sortChange).takeUntil(this.unmount$).subscribe((e:IDatatableSortEvent) =>
this.fetchUserDataSource(this.currentPagination.currentPage, this.currentPagination.itemsPerPage, e.sortBy, e.sortType)
);
Observable.from(this.pagination.paginationChange).takeUntil(this.unmount$).subscribe((e:IDatatablePaginationEvent) =>
this.fetchUserDataSource(e.page, e.itemsPerPage)
);
}
}
ngOnDestroy() {
this.unmount$.next();
this.unmount$.complete();
}
shuffleData() {
this.users$.next(shuffle(this.users$.getValue()));
this.currentSelection$.next([]);
this.changeDetectorRef.detectChanges();
}
private fetchUserDataSource(page:number = this.currentPagination.currentPage, limit:number = this.currentPagination.itemsPerPage, sortBy:string | undefined = this.currentSortBy, sortType:DatatableSortType = this.currentSortType) {
if (sortBy) {
this.currentSortBy = sortBy;
this.currentSortType = sortType;
}
const { users, pagination } = this.listUserService.getUserDatasource( page, limit, sortBy, sortType);
this.users$.next(users);
this.currentSelection$.next([]);
this.currentPagination = pagination;
}
}
you MUST subscribe in an ngOnInit to this.listUserService.getUserDataSource in your list-user-component
export class ListUsersComponent implements OnInit,...
{
page:number=1;
limit:number=5;
sortBy:string='';
....
ngOnInit() {
this.listUserService.getUserDataSource(page, limit, sortBy, sortType).subscribe((res)=>{
....here ...
}
}