mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
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:
committed by
mmalerba
parent
540226c3f9
commit
7747e66ed4
@@ -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'}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user