45
votes

I am creating a Toolbar with a selection list (checkboxes with each list item) using Angular Material 2. I just cannot figure out how to set the checkboxes before the list is displayed and then get the selected items following user interaction.

I am trying the control within a Form thinking I may need this to bind to ngModel, but this doesn't seem to help. My html so far is:

<form
  novalidate
  #areaSelectForm="ngForm">

<div>
    <mat-selection-list 
                        #areasList="ngModel"
                        [(ngModel)]="model"
                        id="areaListControl"
                        name="areaListControl"
                        (ngModelChange)="onAreaListControlChanged($event)">
        <mat-list-option *ngFor="let tta of taskTypeAreas" (click)="onCheckboxClick($event)" [value]="tta">
            {{tta}}
        </mat-list-option>
    </mat-selection-list>
</div>

</form>

This must be a well trodden path but the documentation is difficult to interpret and I cannot seem to find any suitable examples.

Any guidance very welcome please.

3

3 Answers

96
votes

As of version 5.0.0, angular material now supports ngModel for selection list.

So the code can be simplified to

<mat-selection-list #list [(ngModel)]="selectedOptions" (ngModelChange)="onNgModelChange($event)">
    <mat-list-option *ngFor="let tta of taskTypeAreas" [value]="tta.name">
        {{tta.name}}
    </mat-list-option>
</mat-selection-list>

The release also exposes an ngModelChange event for selection list. Here is the updated stack blitz


(Original answer before Angular 5.0.0)

It appears mat-selection-list does not currently support ngModel (https://github.com/angular/material2/pull/7456), but it looks like it will be supported in the near future. In the meantime you can use a reference variable #list to grab the selected options.

// component.html
<mat-selection-list #list>
    <mat-list-option *ngFor="let tta of taskTypeAreas" [selected]="tta.selected" 
        (click)="onAreaListControlChanged(list)" [value]="tta.name">
        {{tta.name}}
    </mat-list-option>
</mat-selection-list>

Then pass in the reference variable to your onAreaListControlChanged(list) method so you can parse out the selected options.

// component.ts
onAreaListControlChanged(list){
    this.selectedOptions = list.selectedOptions.selected.map(item => item.value);
}

To select the checkboxes on load, you can use the [selected] property of each <mat-list-option>.

<mat-list-option ... [selected]="tta.selected" ...>

To do this you'll need to add another property to your array.

// component.ts
taskTypeAreas: {
    name: string;
    selected: boolean;
}[] = [
    {
        name: 'Area 1',
        selected: false
    },
    {
        name: 'Area 2',
        selected: false
    },
    {
        name: 'Area 3',
        selected: true
    },
];

This will make Area 3 be selected on load. Here is a stackblitz demoing this.


13
votes

@LLai's answer is correct, but you might have noticed that Angular material selection does not work when we use object as a mat-select-option [value]

To fix this, Angular material provides [compareWith] input.

@Input() compareWith: (o1: any, o2: any) => boolean

Function used for comparing an option against the selected value when determining which options should appear as selected. The first argument is the value of an options. The second one is a value from the selected value. A boolean must be returned.

For example,

list-selection.component.ts

export class ListSelectionExample {

  selectedOptions = [{name: 'Boots', id:1}];
  compareFunction = (o1: any, o2: any)=> o1.id===o2.id;

  typesOfShoes: {name: string, id: number }[] = [
    {name: 'Boots', id: 1}, 
    {name: 'Clogs', id: 2},
    {name: 'Loafers', id: 3 },
    {name: 'Moccasins', id: 4},
    {name: 'Sneakers', id:5}
  ];
}

list-selection.component.html

<mat-selection-list [(ngModel)]="selectedOptions" [compareWith]="compareFunction">
  <mat-list-option *ngFor="let shoe of typesOfShoes" [value]="shoe">
    {{shoe.name}}
  </mat-list-option>
</mat-selection-list>

<p>
  Options selected: {{selectedOptions | json}}
</p>

Find here the live Stackblitz example

12
votes

You can use the selectionChange event emitter to trigger a controller function.

<mat-selection-list 
   id="areaListControl"
   name="areaListControl"
   (selectionChange)="onChange($event)"
>
    <mat-list-option 
       *ngFor="let tta of taskTypeAreas" 
       [selected]="tta.selected"
       [value]="tta"
    >
        {{tta}}
    </mat-list-option>
</mat-selection-list>

And in the controller:

onChange(change: MatSelectionListChange) {
   console.log(change.option.value, change.option.selected);
}