Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 life cycle hook after all children are initialized?

Tags:

angular

I am looking for a concept to implement the following case:

I have a parent search component that has some components as view children / content children for displaying facets and search results. I now want to trigger a search when the application has finished loading so the user does not see an empty page.

My problem now is that I cannot find a lifecycle hook that fits my needs. The facets / search results subscribe to the search results in their respective ngOnInit. So I need a hook that gets called after all child components had finished initializing.

I have tried the following hooks on the parent component

  • ngAfterContentInit: this gets called before ngOnInit is called on the children
  • ngAfterViewInit: this one works but after the search results return the view of the children gets updated which leads to an error since actions that manipulate the view are not allowed in ngAfterViewInit

Any Idea how to tackle this problem? To me it seems I do not grasp something fundamental here.

Cheers

Tom

like image 753
Tom Avatar asked Aug 04 '16 09:08

Tom


People also ask

Which lifecycle hook is called after Angular has finished initializing all data bound properties?

ngOnInit is a life cycle hook called by Angular 2 to indicate that Angular is done creating the component.

Which lifecycle hook is fired when a component is initialized?

ngOnInit fires once upon initialization of a component's input-bound ( @Input ) properties.

What is the correct order of lifecycle hooks in Angular?

Lifecycle sequenceInitialize the directive/component after Angular first displays the data-bound properties and sets the directive/component's input properties. Called once, after the first ngOnChanges() . Detect and act upon changes that Angular can't or won't detect on its own.

What is the life cycle hook called by Angular During the component initialization?

ngOnChanges This is one of the lifecycle hooks which can come in handy in multiple use cases. It is very useful if you need to handle any specific logic in the component based on the received input property. Check the console , we should see that the console.


2 Answers

I ended up using the ngAfterViewInit() hook in the following way:

ngAfterViewInit(){   //stuff that doesn't do view changes   setTimeout(_=> this.methodThatKicksOffAnotherRoundOfChanges()); } 

This should be safe to use compared to other invocations of setTimeout where an actual time is set, since it should start instantly (and just affect the threading/context behaviour)

like image 190
Tom Avatar answered Oct 14 '22 09:10

Tom


If you need your Parent Component to await custom asynchronous behaviour across multiple child components then here's a good solution I cooked up.

Any child component's that initialise asynchronously extend this:

import {Subject} from 'rxjs/Subject'; import {Observable} from 'rxjs/Observable';  export class AsynchronouslyInitialisedComponent {   loadedState: Subject<boolean> = new Subject<boolean>();   loadedState$ = this.loadedState.asObservable();   constructor() {   }   protected componentLoaded() {     this.loadedState.next(true);   } } 

Example Child component:

import {Component} from '@angular/core'; import {AsynchronouslyInitialisedComponent} from './../base_component';  @Component({   moduleId: module.id,   selector: 'child' }) export class Child extends AsynchronouslyInitialisedComponent {   constructor() {     super();   }   ngOnInit() {     //Some async behavoir:     setTimeout(() => {       this.componentLoaded();     }, 10000);   } } 

Now all your Parent component needs to do is the following:

import {Component, ViewEncapsulation, ViewChild}; import {Observable} from 'rxjs/Observable'; import 'rxjs/add/observable/zip';  @Component({   moduleId: module.id,   selector: 'parent' }) export class Parent {     @ViewChild('child') child; //Just use <child #child></child> in your template    constructor() {   }   ngOnInit() {     Observable     .zip(this.child.loadedState$, this.otherChild.loadedState$) //Add as many as you want here...      .subscribe(pair => {       console.log('All child components loaded');     });   } } 
like image 43
williamsandonz Avatar answered Oct 14 '22 09:10

williamsandonz