Skip to content

Commit ac5913e

Browse files
committed
feat(select): allow for option sorting logic to be customized
Adds an input for a `sortComparator` to `mat-select`. The new input allows consumers to override the logic that `mat-select` uses to sort its values. Fixes #11871.
1 parent a1aa9e7 commit ac5913e

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

src/lib/select/select.spec.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3837,6 +3837,29 @@ describe('MatSelect', () => {
38373837
expect(fixture.componentInstance.control.value).toEqual(['steak-0', 'pizza-1', 'tacos-2']);
38383838
}));
38393839

3840+
it('should be able to customize the value sorting logic', fakeAsync(() => {
3841+
fixture.componentInstance.sortComparator = (a, b, optionsArray) => {
3842+
return optionsArray.indexOf(b) - optionsArray.indexOf(a);
3843+
};
3844+
fixture.detectChanges();
3845+
3846+
trigger.click();
3847+
fixture.detectChanges();
3848+
flush();
3849+
3850+
const options = overlayContainerElement.querySelectorAll('mat-option') as
3851+
NodeListOf<HTMLElement>;
3852+
3853+
for (let i = 0; i < 3; i++) {
3854+
options[i].click();
3855+
}
3856+
fixture.detectChanges();
3857+
3858+
// Expect the items to be in reverse order.
3859+
expect(trigger.textContent).toContain('Tacos, Pizza, Steak');
3860+
expect(fixture.componentInstance.control.value).toEqual(['tacos-2', 'pizza-1', 'steak-0']);
3861+
}));
3862+
38403863
it('should sort the values that get set via the model based on the panel order',
38413864
fakeAsync(() => {
38423865
trigger.click();
@@ -4307,7 +4330,8 @@ class FloatLabelSelect {
43074330
selector: 'multi-select',
43084331
template: `
43094332
<mat-form-field>
4310-
<mat-select multiple placeholder="Food" [formControl]="control">
4333+
<mat-select multiple placeholder="Food" [formControl]="control"
4334+
[sortComparator]="sortComparator">
43114335
<mat-option *ngFor="let food of foods"
43124336
[value]="food.value">{{ food.viewValue }}
43134337
</mat-option>
@@ -4330,6 +4354,7 @@ class MultiSelect {
43304354

43314355
@ViewChild(MatSelect) select: MatSelect;
43324356
@ViewChildren(MatOption) options: QueryList<MatOption>;
4357+
sortComparator: (a: MatOption, b: MatOption, options: MatOption[]) => number;
43334358
}
43344359

43354360
@Component({

src/lib/select/select.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
382382
}
383383

384384
/**
385-
* A function to compare the option values with the selected values. The first argument
385+
* Function to compare the option values with the selected values. The first argument
386386
* is a value from an option. The second is a value from the selection. A boolean
387387
* should be returned.
388388
*/
@@ -416,9 +416,16 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
416416
/** Input that can be used to specify the `aria-labelledby` attribute. */
417417
@Input('aria-labelledby') ariaLabelledby: string;
418418

419-
/** An object used to control when error messages are shown. */
419+
/** Object used to control when error messages are shown. */
420420
@Input() errorStateMatcher: ErrorStateMatcher;
421421

422+
/**
423+
* Function used to sort the values in a select in multiple mode.
424+
* Follows the same logic as `Array.prototype.sort`.
425+
*/
426+
@Input() sortComparator: (a: MatOption, b: MatOption, options: MatOption[]) => number =
427+
(a, b, options) => options.indexOf(a) - options.indexOf(b)
428+
422429
/** Unique id of the element. */
423430
@Input()
424431
get id(): string { return this._id; }
@@ -920,7 +927,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
920927
private _sortValues() {
921928
if (this.multiple) {
922929
const options = this.options.toArray();
923-
this._selectionModel.sort((a, b) => options.indexOf(a) - options.indexOf(b));
930+
this._selectionModel.sort((a, b) => this.sortComparator(a, b, options));
924931
this.stateChanges.next();
925932
}
926933
}

0 commit comments

Comments
 (0)