Search code examples
javascriptangularangular-materialngrxangular-reactive-forms

Angular, NgRx: FormControl patchValue() fails with "Cannot assign to read only property '_pendingValue'"


I have ParentComponent and ChildComponent. Both components make up together a search form with some advanced features. I am using NgRx to manage app state.

When I trigger state update in ngOnDestroy() of ChildComponent, to save childDropdown value before it gets destroyed, then in ParentComponent in state subscription I get following error:

TypeError: Cannot assign to read only property '_pendingValue'

Simplified template:

<app-parent>
    <form [formGroup]="searchForm">

        <mat-form-field>
            <mat-select
                [formControlName]="parentDropdown.controlName"
                [(value)]="parentDropdown.value"
                (selectionChange)="onSelectionChange(parentDropdown.value)"
            >
                <mat-option *ngFor="let item of parentDropdown.data" [value]="item">{{ item.name }}</mat-option>
            </mat-select>
        </mat-form-field>

        <app-child>
            <mat-form-field>
                <mat-select
                    [formControlName]="childDropdown.controlName"
                    [(value)]="childDropdown.value"
                    (selectionChange)="onSelectionChange(childDropdown.value)"
                >
                    <mat-option *ngFor="let item of childDropdown.data" [value]="item">{{ item.name }}</mat-option>
                </mat-select>
            </mat-form-field>
        </app-child>
    </form>
</app-parent>

In ngOnDestroy of ChildComponent actions is dispatched to save value of childDropdown to state:

ngOnDestroy(): void {
    this.store.dispatch(fromSearchActions.UPDATE_CHILD_DROPDOWN({ value: childDropdown.value }));
}

In ngOnInit of ParentComponent the value of parentDropdown gets refreshed from state:

ngOnInit(): void {
    this.store
        .select(getSearchState)
        .subscribe((state: SearchState) => {
            
            this.parentDropdown.value = state.parentDropdown.value;
            this.searchForm
                .get(this.parentDropdown.controlName)
                .patchValue(state.parentDropdown.value); // HERE it fails
        });
}

Error started to occur only after dispatching action in ngOnDestroy of ChildComponent.

For some reason _pendingValue of parentDropdown FormControl becomes readonly.

Descriptor of _pendingValue value property of FormControl

Any idea what's going on?


Solution

  • Found the cause of the above error. I've accidentally saved FormControl into NgRx store, which made all properties of FormControl read-only.

    Fix is, not to save FormControl into store, but only a value, which can be then easily restored/reassigned.