feat(selection-list): add support for compareWith function (#10501)

Similarly to `mat-select`, these changes add an input for a `compareWith` function to the selection list. The input allows consumers to set some custom logic for determining which options is selected, which is useful for cases where the value of a list option is an entire object.
This commit is contained in:
Kristiyan Kostadinov
2018-04-19 11:44:31 -06:00
committed by mmalerba
parent 540226c3f9
commit 7747e66ed4
2 changed files with 57 additions and 7 deletions
+46 -1
View File
@@ -5,7 +5,13 @@ import {
dispatchEvent,
dispatchKeyboardEvent,
} from '@angular/cdk/testing';
import {Component, DebugElement, ChangeDetectionStrategy} from '@angular/core';
import {
Component,
DebugElement,
ChangeDetectionStrategy,
QueryList,
ViewChildren,
} from '@angular/core';
import {async, ComponentFixture, fakeAsync, TestBed, tick, flush} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {
@@ -620,6 +626,7 @@ describe('MatSelectionList with forms', () => {
SelectionListWithPreselectedOption,
SelectionListWithPreselectedOptionAndModel,
SelectionListWithPreselectedFormControlOnPush,
SelectionListWithCustomComparator,
]
});
@@ -842,6 +849,24 @@ describe('MatSelectionList with forms', () => {
}));
});
describe('with custom compare function', () => {
it('should use a custom comparator to determine which options are selected', fakeAsync(() => {
const fixture = TestBed.createComponent(SelectionListWithCustomComparator);
const testComponent = fixture.componentInstance;
testComponent.compareWith = jasmine.createSpy('comparator', (o1, o2) => {
return o1 && o2 && o1.id === o2.id;
}).and.callThrough();
testComponent.selectedOptions = [{id: 2, label: 'Two'}];
fixture.detectChanges();
tick();
expect(testComponent.compareWith).toHaveBeenCalled();
expect(testComponent.optionInstances.toArray()[1].selected).toBe(true);
}));
});
});
@@ -1004,3 +1029,23 @@ class SelectionListWithPreselectedFormControlOnPush {
opts = ['opt1', 'opt2', 'opt3'];
formControl = new FormControl(['opt2']);
}
@Component({
template: `
<mat-selection-list [(ngModel)]="selectedOptions" [compareWith]="compareWith">
<mat-list-option *ngFor="let option of options" [value]="option">
{{option.label}}
</mat-list-option>
</mat-selection-list>`
})
class SelectionListWithCustomComparator {
@ViewChildren(MatListOption) optionInstances: QueryList<MatListOption>;
selectedOptions: {id: number, label: string}[] = [];
compareWith?: (o1: any, o2: any) => boolean;
options = [
{id: 1, label: 'One'},
{id: 2, label: 'Two'},
{id: 3, label: 'Three'}
];
}
+11 -6
View File
@@ -279,6 +279,13 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
/** Tabindex of the selection list. */
@Input() tabIndex: number = 0;
/**
* 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.
*/
@Input() compareWith: (o1: any, o2: any) => boolean;
/** The currently selected options. */
selectedOptions: SelectionModel<MatListOption> = new SelectionModel<MatListOption>(true);
@@ -437,17 +444,15 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
this._onTouched = fn;
}
/** Returns the option with the specified value. */
private _getOptionByValue(value: string): MatListOption | undefined {
return this.options.find(option => option.value === value);
}
/** Sets the selected options based on the specified values. */
private _setOptionsFromValues(values: string[]) {
this.options.forEach(option => option._setSelected(false));
values
.map(value => this._getOptionByValue(value))
.map(value => {
return this.options.find(option =>
this.compareWith ? this.compareWith(option.value, value) : option.value === value);
})
.filter(Boolean)
.forEach(option => option!._setSelected(true));
}