1
votes

I am storing FormArray value in ngrx Store whenever any of the control's value changes.

Form Array has 47 Form Groups and each Form Group has a single Form Control.

I have a parent FormGroup which has 10 Form Arrays for 10 different data sets. and those 10 Form Arrays can have various number of FormGroup with a single Form Control.

What I have noticed is that when I change a value of a control. I can see it changing in the valueChange event handler and this is where I am pushing the updated value in ngrx.

if I go to a different data set; I can see in console that master form has the updated value for the control that I changed.

However, if I come back to the same data set; valueChanges gets fired automatically and it is trying to set the older value for the control that I changed.

I have a guard clause to only continue within valueChanges if control is dirty wh ich works in normal situations however, it is creating a situation for me as this time the control is dirty and the older value is written and pushed to ngrx as well.

i need to figure out why valueChanges is getting triggered and why is it getting triggered with the older value when i can see that parent form did have the right value before re-visiting the dataset where I made the change.

On re-rendering, if I am checking if Form Array values exist in ngrx store or not. If yes then I patchValue the FormArray I have with the FormArray values that I previously stored upon value changes.

I can see that form array values coming ngrx store has the update value but when I call

this.formArray.patchValue(formArrayValue);

I see the valueChanges is called but with old values and after patchValue - this.formArray still have the old values.

Am I doing something wrong here or missing something.

Code Snippets

this is how I am creating control within form group and adding them to form Array.

const fg: any = {};     
const rules = this.validationRules.filter(vc => vc.AttributeName.toLowerCase() === prop.key.toLowerCase());

     fg[key] = this.createControl(rules);
         if (value) {
                fg[key].setValue(value,
                 {
                    onlySelf: true,
                    emitEvent: false,
                    emitModelToViewChange: false,
                    emitViewToModelChange: false
                   });
            }

           const formGroup = new FormGroup(fg);
           this.controlsArray.push(formGroup);

This is how i am trying to patch Value my Form Array in ngOnChanges

this.store.pipe(select(fromForms.getFormsState))
.pipe(take(1))
.subscribe(f => {
    const formArray = f.forms.forms[tableName];
    if (formArray) {
        this.controlsArray.patchValue(formArray);
    }
}); 

I will try to add some code snippets if that helps.

Thanks

1
any reason why the FormArray has nested FormGroups with nested FormControls? Paste your code so we can help better - Sergio Alen
when you say "this.formArray still have the old values" are you seeing those values in the UI or console? - Sergio Alen
@SergioAlen - i am seeing the old value both in UI and console. I have almost 10 different data sets and I am showing them dynamically using a single component. Depending on which data set is clicked; I grab the data from ngrx and hydrate the component. - Robert Dinaro
@SergioAlen - I have updated my question with some more details and a little finding I did in the mean time. - Robert Dinaro
It's hard to see where the issue could be. Are you implementing ControlValueAccessor in your components? Have you tried using the ChangeDetectorRef method markForCheck() or detectChanges() after the value changes subscription is triggered? - Sergio Alen

1 Answers

0
votes
<mat-form-field>
   <input type="text" matInput placeholder="{{ label }}" [formControlName]="key" [readonly]="!isEditable" [(ngMode)]="value">
</mat-form-field>

I had [(ngMode)]="value" on the input control and I am building a Reactive form. Although my FormGroup did change but when the form got rendered it kept looking at the model which wasn't updated and hence it forced FormGroup to have the older value as well.

So please make sure you check for unnecessary [(ngMode)]="value" .