snusnu
snusnu

Reputation: 53

How to wait for multiple input changes on child components?

I am trying to learn Angular 2 and am trying to figure out the best way to implement some functionality with change detection. Basically I have a structure of components like this:

<parent-component>
    <child-component [input]="getData(1) | async"></child-component>
    <child-component [input]="getData(2) | async"></child-component>
</parent-component>

What I want to do is to detect when the inputs for the child components get updated in the same digest cycle, and then call some function in the parent component class. In this way I can use the parent component to process multiple changes at once, rather than process each change one-at-a-time. Is it possible to do this?

Upvotes: 0

Views: 3760

Answers (4)

Jeffrey Haskell
Jeffrey Haskell

Reputation: 115

Build an AND function in your parent component. This assumes you have @Outputs on your child components firing off events when the inputs are submitted.

<parent-component>
<child-component (submitted)="increaseState()" [input]="getData(1) | async"></child-component>
<child-component (submitted)="increaseState()" [input]="getData(2) | async"></child-component>
</parent-component>

Parents .ts

state = 0;

increaseState(){
this.state++
}

function()    {
  if(state === 2)   {
     *process values*
   }
}

Upvotes: 0

bryan60
bryan60

Reputation: 29335

combine them with zip or combineLatest

in the component:

//now filtering out falsey values for getData
// make it .filter(v => v !== undefined) to ignore undefined specifically
dataOne$ = getData(1).filter(v => v);
dataTwo$ = getData(2).filter(v => v);

combined$ = Observable.zip(dataOne$, dataTwo$).do(e => console.log('do whatever you want here');

Or:

combined$ = Observable.combineLatest(dataOne$, dataTwo$).do(e => console.log('do whatever you want here');

in template:

<parent-component *ngIf="combined$ | async as combined">
  <child-component [input]="combined[0]"></child-component>
  <child-component [input]="combined[1]"></child-component>
</parent-component>

Or possibly:

<parent-component >
  <child-component *ngFor="let input of combined$ | async" [input]="input"></child-component>
</parent-component>

The first will make the parent and children instantiate only when combined resolves at least once.

the second will have the parent instantiate immediately, but the children won't instantiate until both items have resolved once.

There is a subtle benefit to the first option, in that the parent component's change detection will trigger everytime the observable it is subscribed to in async updates if you are using onpush change detection, it will not in the second case, though the do operator will always fire no matter what.

zip will fire when only both observables update, and give you the value in pairs

combineLatest will fire everytime one of them fires (AFTER both have fired once) and give you the latest value from the other.

Upvotes: 1

Zhang Bruce
Zhang Bruce

Reputation: 914

in your .ts file set vars

var data1;
var data2;

constructor()
{
  getData1().then((d)=>{data1=d})
  getData2().then((d)=>{data2=d})
}

in your html do

<parent-component>
    <child-component *ngIf="data1 && dat2" [input]="getData(1) | async"></child-component>
    <child-component *ngIf="data1 && dat2" [input]="getData(2) | async"></child-component>
</parent-component>

Upvotes: 0

Max Koretskyi
Max Koretskyi

Reputation: 105517

You can use ngAfterViewChecked lifecycle hook. All hooks are part of change detection as explained in the Everything you need to know about change detection in Angular. The bindings update of the child components is performed as the first operation when Angular runs change detection for the current component. ngAfterViewChecked is the hook that is triggered when the change detection for the current view component is finished.

Upvotes: 0

Related Questions