Skip to content

Commit 14cdd89

Browse files
ogixjelbourn
authored andcommitted
fix(material/select): fix recursive call to SelectionModel.select() (#17071)
Checks if option selection state in SelectionModel is different than the option selected value. Fixes "Maximum call stack size exceeded" error.
1 parent e66de46 commit 14cdd89

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

src/material/select/select.spec.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3905,7 +3905,10 @@ describe('MatSelect', () => {
39053905
});
39063906

39073907
describe('with multiple selection', () => {
3908-
beforeEach(async(() => configureMatSelectTestingModule([MultiSelect])));
3908+
beforeEach(async(() => configureMatSelectTestingModule([
3909+
MultiSelect,
3910+
MultiSelectWithLotsOfOptions
3911+
])));
39093912

39103913
let fixture: ComponentFixture<MultiSelect>;
39113914
let testInstance: MultiSelect;
@@ -4286,6 +4289,18 @@ describe('MatSelect', () => {
42864289
expect(testInstance.control.value).toEqual([]);
42874290
});
42884291

4292+
it('should not throw when selecting a large amount of options', fakeAsync(() => {
4293+
fixture.destroy();
4294+
4295+
const lotsOfOptionsFixture = TestBed.createComponent(MultiSelectWithLotsOfOptions);
4296+
4297+
expect(() => {
4298+
lotsOfOptionsFixture.componentInstance.checkAll();
4299+
lotsOfOptionsFixture.detectChanges();
4300+
flush();
4301+
}).not.toThrow();
4302+
}));
4303+
42894304
});
42904305
});
42914306

@@ -5062,3 +5077,25 @@ class SelectWithFormFieldLabel {
50625077
class SelectWithNgIfAndLabel {
50635078
showSelect = true;
50645079
}
5080+
5081+
@Component({
5082+
template: `
5083+
<mat-form-field>
5084+
<mat-select multiple [ngModel]="value">
5085+
<mat-option *ngFor="let item of items" [value]="item">{{item}}</mat-option>
5086+
</mat-select>
5087+
</mat-form-field>
5088+
`
5089+
})
5090+
class MultiSelectWithLotsOfOptions {
5091+
items = new Array(1000).fill(0).map((_, i) => i);
5092+
value: number[] = [];
5093+
5094+
checkAll() {
5095+
this.value = [...this.items];
5096+
}
5097+
5098+
uncheckAll() {
5099+
this.value = [];
5100+
}
5101+
}

src/material/select/select.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,10 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
947947
this._selectionModel.clear();
948948
this._propagateChanges(option.value);
949949
} else {
950-
option.selected ? this._selectionModel.select(option) : this._selectionModel.deselect(option);
950+
if (wasSelected !== option.selected) {
951+
option.selected ? this._selectionModel.select(option) :
952+
this._selectionModel.deselect(option);
953+
}
951954

952955
if (isUserInput) {
953956
this._keyManager.setActiveItem(option);

0 commit comments

Comments
 (0)