Skip to content

Commit

Permalink
feat(select): allow for option sorting logic to be customized (#11890)
Browse files Browse the repository at this point in the history
  • Loading branch information
crisbeto authored and josephperrott committed Jul 18, 2018
1 parent d6ca3ec commit d54a75a
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 4 deletions.
27 changes: 26 additions & 1 deletion src/lib/select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3850,6 +3850,29 @@ describe('MatSelect', () => {
expect(fixture.componentInstance.control.value).toEqual(['steak-0', 'pizza-1', 'tacos-2']);
}));

it('should be able to customize the value sorting logic', fakeAsync(() => {
fixture.componentInstance.sortComparator = (a, b, optionsArray) => {
return optionsArray.indexOf(b) - optionsArray.indexOf(a);
};
fixture.detectChanges();

trigger.click();
fixture.detectChanges();
flush();

const options = overlayContainerElement.querySelectorAll('mat-option') as
NodeListOf<HTMLElement>;

for (let i = 0; i < 3; i++) {
options[i].click();
}
fixture.detectChanges();

// Expect the items to be in reverse order.
expect(trigger.textContent).toContain('Tacos, Pizza, Steak');
expect(fixture.componentInstance.control.value).toEqual(['tacos-2', 'pizza-1', 'steak-0']);
}));

it('should sort the values that get set via the model based on the panel order',
fakeAsync(() => {
trigger.click();
Expand Down Expand Up @@ -4320,7 +4343,8 @@ class FloatLabelSelect {
selector: 'multi-select',
template: `
<mat-form-field>
<mat-select multiple placeholder="Food" [formControl]="control">
<mat-select multiple placeholder="Food" [formControl]="control"
[sortComparator]="sortComparator">
<mat-option *ngFor="let food of foods"
[value]="food.value">{{ food.viewValue }}
</mat-option>
Expand All @@ -4343,6 +4367,7 @@ class MultiSelect {

@ViewChild(MatSelect) select: MatSelect;
@ViewChildren(MatOption) options: QueryList<MatOption>;
sortComparator: (a: MatOption, b: MatOption, options: MatOption[]) => number;
}

@Component({
Expand Down
16 changes: 13 additions & 3 deletions src/lib/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
}

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

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

/**
* Function used to sort the values in a select in multiple mode.
* Follows the same logic as `Array.prototype.sort`.
*/
@Input() sortComparator: (a: MatOption, b: MatOption, options: MatOption[]) => number;

/** Unique id of the element. */
@Input()
get id(): string { return this._id; }
Expand Down Expand Up @@ -920,7 +926,11 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
private _sortValues() {
if (this.multiple) {
const options = this.options.toArray();
this._selectionModel.sort((a, b) => options.indexOf(a) - options.indexOf(b));

this._selectionModel.sort((a, b) => {
return this.sortComparator ? this.sortComparator(a, b, options) :
options.indexOf(a) - options.indexOf(b);
});
this.stateChanges.next();
}
}
Expand Down

0 comments on commit d54a75a

Please sign in to comment.