angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.32k stars 6.73k forks source link

mat-selection-list list-options is not updated when formControl for mat-selection-list is updated with setValue #15477

Open EmilienRamos opened 5 years ago

EmilienRamos commented 5 years ago

What is the expected behavior?

Checkboxes should update

What is the current behavior?

Checkboxes do not update.

What are the steps to reproduce?

editor.componenet.html

<mat-selection-list formControlName="role">
    <mat-list-option checkboxPosition="before" *ngFor="let role of roles" [value]="role.id">{{ role.attributes.name }}</mat-list-option>
</mat-selection-list>

editor.component.ts (onInit)

this.form = this.fb.group({
    role: [[...this.user.attributes.role], Validators.required],
});

this.user.attributes.role is an array of string.

I tried editor.component.ts

ngAfterContentInit() {
    this.form.patchValue({
        'role': [...this.user.attributes.role]
    });
}

I also tried editor.component.ts

ngAfterContentInit() {
    setTimeout(() => {
      this.form.patchValue({
        'role': [...this.user.attributes.role]
      });
      console.log(this.form.value.role);
    }, 1000);
}

Note that I'm getting roles with an observable : editor.component.ts

combineLatest(
      // Others observables ...
      this.jsonApi.all('roles').pipe(map(document => document.data)),
    ).subscribe(([firms, langs, roles]) => {
      // Others observables ...
      this.roles = roles;
    });

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Angular 7.x.x Material 7.x.x

Is there anything else we should know?

I know there's a ticket about this, but it's closed and no one replies

SzabKel commented 5 years ago

Same, If I change the values bound, the checkboxes won't update (none is selected). Even though the array is updated correctly If I proceed to check another checkbox. I tried using the compareWith function and using objects and a simple number[] too, did not work.

SzabKel commented 5 years ago

I could trick the component though, by introducing an extra boolean variable showBoundMatSelectionList, which is true by default and I added an *ngIf="showBoundMatSelectionList" for the mat-selection-list component. This way I can force Angular to destroy the component before I do the patchValue call using the injected protected ref: ChangeDetectorRef and reload it afterwards.

this.showBoundMatSelectionList = false;
// now notify angular to check for updates
this.ref.detectChanges();
// do your thing
// patchValues ..etc
this.showBoundMatSelectionList = true;
this.ref.detectChanges();

With this, the mat-selection-list is forced to reload the checkbox values from the supplied array. Does not matter which binding you use.

Check out: https://stackoverflow.com/questions/47496610/destroying-and-reloading-a-child-component