Skip to content

Commit d7031da

Browse files
authored
fix(module:select): ngModel change should update state of nzMaxMultipleCount reached (#9056)
1 parent 9b3f62e commit d7031da

4 files changed

Lines changed: 75 additions & 39 deletions

File tree

‎components/select/option-container.component.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ import { NzSelectItemInterface, NzSelectModeType } from './select.types';
7070
[customContent]="item.nzCustomContent"
7171
[template]="item.template ?? null"
7272
[grouped]="!!item.groupLabel"
73-
[disabled]="item.nzDisabled || (isMaxLimitReached && !listOfSelectedValue.includes(item['nzValue']))"
73+
[disabled]="
74+
item.nzDisabled || (isMaxMultipleCountReached && !listOfSelectedValue.includes(item['nzValue']))
75+
"
7476
[showState]="mode === 'tags' || mode === 'multiple'"
7577
[title]="item.nzTitle"
7678
[label]="item.nzLabel"
@@ -109,7 +111,7 @@ export class NzOptionContainerComponent implements OnChanges, AfterViewInit {
109111
@Input() matchWidth = true;
110112
@Input() itemSize = 32;
111113
@Input() maxItemLength = 8;
112-
@Input() isMaxLimitReached = false;
114+
@Input() isMaxMultipleCountReached = false;
113115
@Input() listOfContainerItem: NzSelectItemInterface[] = [];
114116
@Output() readonly itemClick = new EventEmitter<NzSafeAny>();
115117
@Output() readonly scrollToBottom = new EventEmitter<void>();

‎components/select/select-arrow.component.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { NzIconModule } from 'ng-zorro-antd/icon';
2121
encapsulation: ViewEncapsulation.None,
2222
changeDetection: ChangeDetectionStrategy.OnPush,
2323
template: `
24-
@if (isMaxTagCountSet) {
24+
@if (isMaxMultipleCountSet) {
2525
<span>{{ listOfValue.length }} / {{ nzMaxMultipleCount }}</span>
2626
}
2727
@if (loading) {
@@ -54,7 +54,7 @@ export class NzSelectArrowComponent {
5454
@Input() loading = false;
5555
@Input() search = false;
5656
@Input() showArrow = false;
57-
@Input() isMaxTagCountSet = false;
57+
@Input() isMaxMultipleCountSet = false;
5858
@Input() suffixIcon: TemplateRef<NzSafeAny> | string | null = null;
5959
@Input() feedbackIcon: TemplateRef<NzSafeAny> | string | null = null;
6060
@Input({ transform: numberAttribute }) nzMaxMultipleCount: number = Infinity;

‎components/select/select.component.ts‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export type NzSelectSizeType = NzSizeLDSType;
128128
(deleteItem)="onItemDelete($event)"
129129
(keydown)="onKeyDown($event)"
130130
></nz-select-top-control>
131-
@if (nzShowArrow || (hasFeedback && !!status) || isMaxTagCountSet) {
131+
@if (nzShowArrow || (hasFeedback && !!status) || isMaxMultipleCountSet) {
132132
<nz-select-arrow
133133
[showArrow]="nzShowArrow"
134134
[loading]="nzLoading"
@@ -137,7 +137,7 @@ export type NzSelectSizeType = NzSizeLDSType;
137137
[feedbackIcon]="feedbackIconTpl"
138138
[nzMaxMultipleCount]="nzMaxMultipleCount"
139139
[listOfValue]="listOfValue"
140-
[isMaxTagCountSet]="isMaxTagCountSet"
140+
[isMaxMultipleCountSet]="isMaxMultipleCountSet"
141141
>
142142
<ng-template #feedbackIconTpl>
143143
@if (hasFeedback && !!status) {
@@ -185,7 +185,7 @@ export type NzSelectSizeType = NzSizeLDSType;
185185
[dropdownRender]="nzDropdownRender"
186186
[compareWith]="compareWith"
187187
[mode]="nzMode"
188-
[isMaxLimitReached]="isMaxLimitReached"
188+
[isMaxMultipleCountReached]="isMaxMultipleCountReached"
189189
(keydown)="onKeyDown($event)"
190190
(itemClick)="onItemClick($event)"
191191
(scrollToBottom)="nzScrollToBottom.emit()"
@@ -271,10 +271,14 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
271271
return this._nzShowArrow === undefined ? this.nzMode === 'default' : this._nzShowArrow;
272272
}
273273

274-
get isMaxTagCountSet(): boolean {
274+
get isMaxMultipleCountSet(): boolean {
275275
return this.nzMaxMultipleCount !== Infinity;
276276
}
277277

278+
get isMaxMultipleCountReached(): boolean {
279+
return this.nzMaxMultipleCount !== Infinity && this.listOfValue.length === this.nzMaxMultipleCount;
280+
}
281+
278282
@Output() readonly nzOnSearch = new EventEmitter<string>();
279283
@Output() readonly nzScrollToBottom = new EventEmitter<void>();
280284
@Output() readonly nzOpenChange = new EventEmitter<boolean>();
@@ -320,7 +324,6 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
320324
focused = false;
321325
dir: Direction = 'ltr';
322326
positions: ConnectionPositionPair[] = [];
323-
isMaxLimitReached = false;
324327

325328
// status
326329
prefixCls: string = 'ant-select';
@@ -434,9 +437,6 @@ export class NzSelectComponent implements ControlValueAccessor, OnInit, AfterCon
434437
this.value = model;
435438
this.onChange(this.value);
436439
}
437-
438-
this.isMaxLimitReached =
439-
this.nzMaxMultipleCount !== Infinity && this.listOfValue.length === this.nzMaxMultipleCount;
440440
}
441441

442442
onTokenSeparate(listOfLabel: string[]): void {

‎components/select/select.spec.ts‎

Lines changed: 61 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,13 +1162,15 @@ describe('select', () => {
11621162
describe('multiple reactive mode', () => {
11631163
let component: TestSelectReactiveMultipleComponent;
11641164
let fixture: ComponentFixture<TestSelectReactiveMultipleComponent>;
1165+
let selectComponent: NzSelectComponent;
11651166
let selectElement!: HTMLElement;
11661167
let overlayContainerElement: HTMLElement;
11671168

11681169
beforeEach(() => {
11691170
fixture = TestBed.createComponent(TestSelectReactiveMultipleComponent);
11701171
component = fixture.componentInstance;
11711172
fixture.detectChanges();
1173+
selectComponent = fixture.debugElement.query(By.directive(NzSelectComponent)).componentInstance;
11721174
selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;
11731175
overlayContainerElement = TestBed.inject(OverlayContainer).getContainerElement();
11741176
});
@@ -1332,6 +1334,65 @@ describe('select', () => {
13321334
expect(listOfContainerItem[1]).toHaveClass('ant-select-item-option-disabled');
13331335
}));
13341336

1337+
it('should isMaxMultipleCountSet work correct', () => {
1338+
component.nzMaxMultipleCount = Infinity;
1339+
fixture.detectChanges();
1340+
expect(selectComponent.isMaxMultipleCountSet).toBeFalsy();
1341+
1342+
component.nzMaxMultipleCount = 1;
1343+
fixture.detectChanges();
1344+
expect(selectComponent.isMaxMultipleCountSet).toBeTruthy();
1345+
});
1346+
1347+
it('should isMaxMultipleCountReached be set correctly when click options', fakeAsync(() => {
1348+
const flushRefresh = (): void => {
1349+
fixture.detectChanges();
1350+
flush();
1351+
fixture.detectChanges();
1352+
};
1353+
component.nzOpen = true;
1354+
component.listOfOption = [
1355+
{ value: 'test_01', label: 'test_01' },
1356+
{ value: 'test_02', label: 'test_02' }
1357+
];
1358+
component.value = [];
1359+
component.nzMaxMultipleCount = 1;
1360+
flushRefresh();
1361+
expect(selectComponent.isMaxMultipleCountReached).toBeFalsy();
1362+
const listOfContainerItem = document.querySelectorAll('nz-option-item');
1363+
dispatchMouseEvent(listOfContainerItem[0], 'click');
1364+
flushRefresh();
1365+
expect(selectComponent.isMaxMultipleCountReached).toBeTruthy();
1366+
}));
1367+
1368+
it('should isMaxMultipleCountReached be set correctly when change the ng model value', fakeAsync(() => {
1369+
const options = [
1370+
{ value: 'test_01', label: 'test_01' },
1371+
{ value: 'test_02', label: 'test_02' }
1372+
];
1373+
const flushRefresh = (): void => {
1374+
fixture.detectChanges();
1375+
flush();
1376+
fixture.detectChanges();
1377+
};
1378+
component.nzOpen = true;
1379+
component.listOfOption = options;
1380+
component.value = [];
1381+
component.nzMaxMultipleCount = 1;
1382+
flushRefresh();
1383+
const listOfContainerItem = document.querySelectorAll('nz-option-item');
1384+
expect(selectComponent.isMaxMultipleCountReached).toBeFalsy();
1385+
selectComponent.writeValue([options[0]]);
1386+
flushRefresh();
1387+
expect(selectComponent.isMaxMultipleCountReached).toBeTruthy();
1388+
expect(listOfContainerItem[1]).toHaveClass('ant-select-item-option-disabled');
1389+
selectComponent.writeValue([]);
1390+
flushRefresh();
1391+
expect(selectComponent.isMaxMultipleCountReached).toBeFalsy();
1392+
expect(listOfContainerItem[0]).not.toHaveClass('ant-select-item-option-disabled');
1393+
expect(listOfContainerItem[1]).not.toHaveClass('ant-select-item-option-disabled');
1394+
}));
1395+
13351396
it('should show nzShowArrow component when having nzMaxMultipleCount', () => {
13361397
component.nzMaxMultipleCount = 0;
13371398
expect(selectElement.querySelector('nz-select-arrow')).toBeFalsy();
@@ -1493,33 +1554,6 @@ describe('select', () => {
14931554
// expect(requestAnimationFrameSpy).toHaveBeenCalledTimes(2);
14941555
}));
14951556

1496-
it('should isMaxTagCountSet work correct', () => {
1497-
component.nzMaxMultipleCount = Infinity;
1498-
fixture.detectChanges();
1499-
let isMaxTagCountSet;
1500-
isMaxTagCountSet = selectComponent['isMaxTagCountSet'];
1501-
expect(isMaxTagCountSet).toBeFalsy();
1502-
1503-
component.nzMaxMultipleCount = 1;
1504-
fixture.detectChanges();
1505-
isMaxTagCountSet = selectComponent['isMaxTagCountSet'];
1506-
expect(isMaxTagCountSet).toBeTruthy();
1507-
});
1508-
1509-
it('should isMaxLimitReached be set correctly', () => {
1510-
selectComponent.nzMaxMultipleCount = 2;
1511-
selectComponent.listOfValue = ['a', 'b'];
1512-
fixture.detectChanges();
1513-
selectComponent.updateListOfValue(['a', 'b']);
1514-
expect(selectComponent.isMaxLimitReached).toBeTruthy();
1515-
1516-
selectComponent.nzMaxMultipleCount = 20;
1517-
selectComponent.listOfValue = ['a', 'b'];
1518-
fixture.detectChanges();
1519-
selectComponent.updateListOfValue(['a', 'b']);
1520-
expect(selectComponent.isMaxLimitReached).toBeFalsy();
1521-
});
1522-
15231557
it('should not run change detection when `nz-select-top-control` is clicked and should focus the `nz-select-search`', () => {
15241558
const appRef = TestBed.inject(ApplicationRef);
15251559
spyOn(appRef, 'tick');

0 commit comments

Comments
 (0)