Trying to pass the array value from the parent component to the child component using httpclient get method. So, I have used an input decorator. But, In my code, I am not able to pass the array value. Because the child component is loaded before the parent component. That's why i am not able to pass the data inside the get method. How to resolve this issue?
app.component.ts:
public allData = [];
constructor(private httpClient: HttpClient) {}
ngOnInit(): void {
this.httpClient.get<string[]>('assets/data.json').subscribe((data) => {
this.allData = data;
console.log('GetData');
console.log(data);
});
}
auto.component.ts:
@Input() data: Array<string> = [];
public rateData:any;
constructor() {
}
ngOnInit(): void {
console.log("thisdata");
console.log(this.data)
this.rateData =this.data;
}
Demo: https://stackblitz.com/edit/angular-ivy-1jw62m?file=src/app/auto/auto.component.ts
CodePudding user response:
The problem is that the ngOnInit
lifecycle-hook runs at a specific point in time, after the constructor. Your GET-request is async and resolves at some unknown time, probably way after your child component is created. Thus, way past you child's ngOnInit
has run. Thus, ngOnInit
really has nothing to work with.
You have two options of fixing this: By using the ngOnChanges
hook (a bit complex, not recommended), or by using a setter for the input, which will run whenever the input value changes. The latter I would recommend.
I have forked your project to demonstrate: https://stackblitz.com/edit/angular-ivy-va1se8?file=src/app/auto/auto.component.ts,src/app/auto/auto.component.html,src/app/app.component.ts
CodePudding user response:
You need to implement OnChanges
interface and add ngOnChanges
class method and manually update your field. OnInit recieves null
and it does not get called later.
Docs: https://angular.io/api/core/OnChanges
app.component.ts
import { Component, VERSION, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
name = 'Angular ' VERSION.major;
public readonly allData$: Observable<string[]>;
constructor(private httpClient: HttpClient) {
this.allData$ = this.httpClient.get<string[]>('assets/data.json');
}
ngOnInit(): void {}
}
app.component.html
<hello name="{{ name }}"></hello>
<p>Start editing to see some magic happen :)</p>
<app-auto [data]="allData$ | async"></app-auto>
auto.component.ts
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
@Component({
selector: 'app-auto',
templateUrl: './auto.component.html',
styleUrls: ['./auto.component.css']
})
export class AutoComponent implements OnChanges {
@Input() data: Array<string> = [];
public rateData: string[] = [];
constructor() {
}
ngOnChanges(changes: SimpleChanges) {
this.rateData = changes.data.currentValue;
}
}
auto.component.html
{{ rateData | json }}
CodePudding user response:
The problem is that the call is asynchronous so you have to use tools like ngOnChange hook for get the input change
https://www.stackchief.com/blog/ngOnChanges Example | Angular
CodePudding user response:
Yes you can add an onChanges to your child component and track the changes but if its just a matter of reacting to one single property change you can convert your @Input to setter/getter also e.g.
private _data: string[];
@Input() set data(val: string[]) {
this._data = val;
this.rateData = val;
}
get data(): string[] {
return this._data;
}
However i would suggest that you change your parent component's change detection to OnPush and manually trigger change detection also. In Auto change detection, angualr is running cd unncessarily and you can trigger it only when you receive the data.