On one blog I've read that:
The ngOnInit lifecycle hook is a guarantee that your bindings are readily available.
Is it true also with parameters passed using async pipe? For example:
<myComponent [myInput]="myObservableVariable | async">
...
</myComponent>
Will component wait for the variable to be resolved before starting up ngOnInit?
That would mean that sometimes, when data will take a while to resolve, component loading could take a long time.
The short answer is no, the component instantiation won't be delayed and you will not get a resolved value in onInit
if the observable hasn't been resolved before the first change detection cycle.
Compare the following:
// the value will be available in onInit
obs = Observable.from([33]);
// the value will not be available in onInit (you'll get null)
obs = new Observable(observer => {
setTimeout(() => {
observer.next(33);
}, 1000);
setTimeout(() => {
observer.complete();
}, 3000);
});
<child-component [inputproperty]="obs"><child-component>
Here is what happens under the hood when you use async
pipe:
async
pipe has a method transform
which is called on every change detection cycle. this method is responsible for returning the current resolved value of the observable that will be passed down to a child component. If the observable hasn't been resolved before the first change detection cycle, your child component will get null
in onInit
.
Then, during next digest cycle your binding will be updated as transform
will return resolved values. What's interesting is that resolution of an observable can trigger the change detection cycle. You can obtain new values for the bindings in onChanges
lifecycle hook.
No, the bindings being available doesn't mean that their values have been resolved (and they may change later anyway). You can demonstrate this with a simple example:
import { Component, Input, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Rx';
@Component({
selector: 'sub-component',
template: `<p>{{ myInput }}</p>`,
})
export class SubComponent implements OnInit {
@Input() myInput: string;
ngOnInit() {
console.log('initialised with', this.myInput);
}
}
@Component({
selector: 'my-app',
template: `
<h1>Hello {{name}}</h1>
<sub-component [myInput]="content$ | async"></sub-component>
`
})
export class AppComponent {
name = 'Angular';
content$ = Observable.of('Hello world').delay(5000);
}
https://plnkr.co/edit/jX7hOafuJtsWYhYrJx07?p=preview
In the console you will see initialised with null
, then five seconds later the text will appear in the sub component.
If you want to know when the @Input
data changes, you need to implement 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