Search code examples
angularngrx

Synchronize child component's input with grand parent. Many indirations


I have structure of components as below:

  • main component
    • sub component
      • intermediate component
        • with the <input> component

Main component has changeset object with is populated from ngrx store. I want all with the input components be synchronized with changeset for performance reason and after save button changeset will be applied to ngrx store

Which angular feature should I use, to connect all <input> components to changeset in two-way data binding way.

Example with child -> parent

https://stackblitz.com/edit/angular-ivy-bseiyd?file=src%2Fapp%2Fchild.component.ts

Example with child -> grand parent. And here to make this work I should duplicate event emitter which I think is not best way.

https://stackblitz.com/edit/angular-ivy-a13ztp?file=src%2Fapp%2Fchild.component.ts

One solution which could be consider is reactive forms mentioned by @cogcak but still there is a problem with passing values at the bottom.

In my case, template doesn't look like this:

<form [formGroup]="form">
  <input type="text" formControlName="mainInput">
  <div formGroupName="childGroup">
    <input type="text" formControlName="childInput"
  </div>
</form>

But more or less like this:

<form [formGroup]="form">
  <input type="text" formControlName="mainInput">
  <div formGroupName="childGroup">
    <child-that-has-input> type="text" formControlName="childInput"
  </div>
</form>

Or in reality even:

<form [formGroup]="form">
  <input type="text" formControlName="mainInput">
  <div formGroupName="childGroup">
    <child-that-has-child-which-as-input type="text" formControlName="childInput"
  </div>
</form>

Solution

  • You can use reactive form for the populated set of values coming from store at the init lifecycle of the input component.

    theReativeForm = new fb.group({
       changeSetOfValues: new fb.array([])
    });
    ...
    onInit() {
       const changeState$ = this.store.select(state => state.changeState);
       changeState$.subscribe(values => 
          values.forEach(value => 
             this.theReativeForm
               .get('changeSetOfValues')
               .push(this.fb.control(value)));
       );
    }
    

    then listen every change in the form to sync to the state in store,

    this.theReativeForm.get('changeSetOfValues').valueChanges(valuesFormArray =>
       yourUpdateStateReducerMethod(valuesFormArray.value);
    );