Search code examples
angulartypescriptangular-reactive-formsangular-formsangular-pipe

Filtering checkbox-list in a ReactiveForm leads to rendering error


I have set up a reactive form. It includes regular input fields as well as multiple checkboxes as a list. I included also an input field to filter the checkbox list. While normal characters do not cause any problems, the dot (.) character seems to influence the rendering of the checkboxes.

If you search for "Zwei" everything seems fine. The (checked) checkboxes keep their "checked"-state, even if you delete the search value afterwards.

If you enter now "i.null" in the search field also everything seems OK. Now delete the first two characters and re-enter them; now a (rendering?) problem occurs. The second checkbox ("ZWEI.NULL") is rendered as "checked", but i wasn´t clicked neither marked as "selected" in the controller. If you take a look in the formGroup-debug-console message (by pressing the top button) the "selected"-property is not defined as "true".

Code example: https://stackblitz.com/edit/angular-xuohtg

I expect the checkboxes to keep their checked-state. Do you have any ideas how this effect comes to play?


Solution

  • The core issue is the fact that you are using 2 different arrays in your component: one is the controls array in the FormArray instance (lets call it ModelArray) and the one returned after the filter is processed (lets call it ViewArray).

    They both have the same FormGroup instances, but in different orders. You use ViewArray to generate your view and you map its indexes through the FormArrayName and FormGroupName directives to elements in the ModelArray.

    For an index I with 0 < I < len(ViewArray), you will end up displaying the values of a FormGroup instance A <= ViewArray[I] and binding the view inputs to an instance B <= ModelArray[I], with the possibility of A is B === false

    You can overcome this by binding the FormGroup instances to the FormArrayName by using the FormGroupDirective instead of the FormGroupName directive as follows:

    <div class="form-group"
             formArrayName="permissions">
            <label class="checkboxLabel"
                   *ngFor="let permissionGroup of permissionsControl.controls | LockFilter: filter.value; index as i"
                   [formGroup]="permissionGroup">
                <input type="checkbox"
                       formControlName="selected">
                ({{ i }}){{permissionGroup.value.label}} ({{permissionGroup.value.id}})
            </label>
        </div>
    

    A working example can be found in this blitz