I have a parent component passing in data to a child component from an API like so:
.ts
private loadData() {
this.data = this.apiService.getData();
}
.html
<child [data]="data | async"></child>
Then I have a child component that takes this input data and attempts to display/process it like:
export class Child implements OnInit {
private _data: Data[];
@Input()
set data(value: Data[]) {
this._data = value;
}
get data(): Data[] {
return this._data;
}
constructor() {
}
ngOnInit() {
this.processData();
}
private processData() {
const data = this.data; // this is undefined
// Do processing here
}
}
I know it is because the data is async and when it calls the ngOnInit the data has not reached that component yet but how can I load the data on init or at least update it when the async completes?
There are multiple options I'm thinking of.
The first option is to only create the child component if the API call resolves.
Example:
<ng-content *ngIf="(data | async) as loadedData">
<child [data]="loadedData"></child>
</ng-content>
The other option is to listen for @Input changes in your child component with ngOnChanges:
child.component.ts
@Input() data: Data[];
ngOnChanges(changes: SimpleChanges){
// If changes.data is set the data input has changed
if (changes.data) {
this.processData();
}
}
The SimpleChanges is a hashtable of changes. See ngOnChanges and SimpleChanges for more information ;-)
The last option would be following in my opinion:
child.component.ts
@Input()
set data(value: Data[]) {
this._data = value;
this.processData();
}
With the last option you'd process the data every time the setter is called. It is not much different from the second option.
I'd suggest you the last option, because you don't need to change a lot ;-)
I know this is already answered but I'd like to point out ngOnChanges.
SimpleChanges has very cool props like previousValue and currentValue, so you can make things like this:
ngOnChanges(changes: SimpleChanges) {
const { myExpectedProp } = changes;
if (myExpectedProp.previousValue !== myExpectedProp.currentValue) {
this.doSomething();
}
}
Isn't it awesome? In case you're not using async pipe, this is very handy.
Don't forget to implement the interface:
import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
export class YourComponent implements OnInit, OnChanges {
// ...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With