Skip to content

Commit bc673e7

Browse files
authored
fix: some forms component can't be disable (#7786)
* fix(module:date-picker): nzDatePicker can be always disable * fix(module:checkbox): 🐛 checkbox can be always disable or enable * fix(module:input-number): input-number can be always disable or enable * fix(module:rate): rate can be always disable or enable * fix(module:radio): radio can be always disable or enable * fix(module:select): radio can be always disable or enable * fix(module:checkbox): checkbox can be always disable or enable * fix(module:slider): slider can be always disable or enable * fix(module:time-picker): time-picker can be always disable or enable * refactor(module:cascader): close the menu based on nzDisable property * test(module:checkbox): add missing test on disable behavior with forms * test(module:radio): add missing test on disable behavior with forms * test(module:switch): add missing test on disable behavior with forms * chore: bump custom webpack to v15 * test(module:rate): add missing test on disable behavior with forms * test(module:input-number): add missing test on disable behavior * test(module:select): add missing test on disable behavior * test(module:checkbox): refactor test * test(module:switch): refactor test * test(module:radio): add missing test on disable behavior with forms * test(module:rate): add missing test on disable behavior with forms * test: refactor some test * test(module:slider): add missing test on disable behavior with forms * test(module:timepicker): add missing test on disable behavior * test(module:datepicker): add missing test on disable behavior
1 parent 285655a commit bc673e7

20 files changed

+446
-160
lines changed

components/cascader/cascader.component.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -747,11 +747,11 @@ export class NzCascaderComponent
747747
}
748748

749749
setDisabledState(isDisabled: boolean): void {
750-
if (isDisabled) {
751-
this.closeMenu();
752-
}
753750
this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || isDisabled;
754751
this.isNzDisableFirstChange = false;
752+
if (this.nzDisabled) {
753+
this.closeMenu();
754+
}
755755
}
756756

757757
closeMenu(): void {

components/checkbox/checkbox.component.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export class NzCheckboxComponent implements OnInit, ControlValueAccessor, OnDest
8282

8383
dir: Direction = 'ltr';
8484
private destroy$ = new Subject<void>();
85+
private isNzDisableFirstChange: boolean = true;
8586

8687
onChange: OnChangeType = () => {};
8788
onTouched: OnTouchedType = () => {};
@@ -119,7 +120,8 @@ export class NzCheckboxComponent implements OnInit, ControlValueAccessor, OnDest
119120
}
120121

121122
setDisabledState(disabled: boolean): void {
122-
this.nzDisabled = disabled;
123+
this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || disabled;
124+
this.isNzDisableFirstChange = false;
123125
this.cdr.markForCheck();
124126
}
125127

components/checkbox/checkbox.spec.ts

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { BidiModule, Dir } from '@angular/cdk/bidi';
22
import { ApplicationRef, Component, DebugElement, ViewChild } from '@angular/core';
33
import { ComponentFixture, fakeAsync, flush, TestBed, waitForAsync } from '@angular/core/testing';
4-
import { UntypedFormBuilder, UntypedFormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
4+
import { FormsModule, ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
55
import { By } from '@angular/platform-browser';
66

77
import { NzCheckboxGroupComponent } from './checkbox-group.component';
@@ -221,32 +221,60 @@ describe('checkbox', () => {
221221
describe('checkbox form', () => {
222222
let fixture: ComponentFixture<NzTestCheckboxFormComponent>;
223223
let testComponent: NzTestCheckboxFormComponent;
224-
let checkbox: DebugElement;
225-
let inputElement: HTMLInputElement;
226224

227-
beforeEach(fakeAsync(() => {
225+
beforeEach(() => {
228226
fixture = TestBed.createComponent(NzTestCheckboxFormComponent);
227+
testComponent = fixture.componentInstance;
228+
});
229+
it('should be in pristine, untouched, and valid states and enable initially', fakeAsync(() => {
229230
fixture.detectChanges();
230231
flush();
231-
fixture.detectChanges();
232-
testComponent = fixture.debugElement.componentInstance;
233-
checkbox = fixture.debugElement.query(By.directive(NzCheckboxComponent));
234-
inputElement = checkbox.nativeElement.querySelector('input') as HTMLInputElement;
235-
}));
236-
it('should be in pristine, untouched, and valid states initially', fakeAsync(() => {
237-
flush();
232+
const checkbox = fixture.debugElement.query(By.directive(NzCheckboxComponent));
233+
const inputElement = checkbox.nativeElement.querySelector('input') as HTMLInputElement;
234+
expect(checkbox.nativeElement.firstElementChild!.classList).not.toContain('ant-checkbox-disabled');
235+
expect(inputElement.disabled).toBeFalsy();
238236
expect(testComponent.formGroup.valid).toBe(true);
239237
expect(testComponent.formGroup.pristine).toBe(true);
240238
expect(testComponent.formGroup.touched).toBe(false);
241239
}));
240+
it('should be disable if form is disable and nzDisable set to false', fakeAsync(() => {
241+
testComponent.disable();
242+
fixture.detectChanges();
243+
flush();
244+
const checkbox = fixture.debugElement.query(By.directive(NzCheckboxComponent));
245+
const inputElement = checkbox.nativeElement.querySelector('input') as HTMLInputElement;
246+
expect(checkbox.nativeElement.firstElementChild!.classList).toContain('ant-checkbox-disabled');
247+
expect(inputElement.disabled).toBeTruthy();
248+
}));
242249
it('should set disabled work', fakeAsync(() => {
250+
testComponent.disabled = true;
251+
fixture.detectChanges();
252+
flush();
253+
const checkbox = fixture.debugElement.query(By.directive(NzCheckboxComponent));
254+
const inputElement = checkbox.nativeElement.querySelector('input') as HTMLInputElement;
255+
256+
expect(checkbox.nativeElement.firstElementChild!.classList).toContain('ant-checkbox-disabled');
257+
expect(inputElement.disabled).toBeTruthy();
258+
inputElement.click();
243259
flush();
260+
fixture.detectChanges();
244261
expect(testComponent.formGroup.get('checkbox')!.value).toBe(false);
262+
263+
testComponent.enable();
264+
fixture.detectChanges();
265+
flush();
266+
expect(checkbox.nativeElement.firstElementChild!.classList).not.toContain('ant-checkbox-disabled');
267+
expect(inputElement.disabled).toBeFalsy();
245268
inputElement.click();
246269
flush();
247270
fixture.detectChanges();
248271
expect(testComponent.formGroup.get('checkbox')!.value).toBe(true);
272+
249273
testComponent.disable();
274+
fixture.detectChanges();
275+
flush();
276+
expect(checkbox.nativeElement.firstElementChild!.classList).toContain('ant-checkbox-disabled');
277+
expect(inputElement.disabled).toBeTruthy();
250278
inputElement.click();
251279
flush();
252280
fixture.detectChanges();
@@ -425,12 +453,13 @@ export class NzTestCheckboxWrapperComponent {
425453
@Component({
426454
template: `
427455
<form [formGroup]="formGroup">
428-
<label nz-checkbox formControlName="checkbox"></label>
456+
<label nz-checkbox formControlName="checkbox" [nzDisabled]="disabled"></label>
429457
</form>
430458
`
431459
})
432460
export class NzTestCheckboxFormComponent {
433461
formGroup: UntypedFormGroup;
462+
disabled = false;
434463

435464
constructor(private formBuilder: UntypedFormBuilder) {
436465
this.formGroup = this.formBuilder.group({
@@ -441,6 +470,10 @@ export class NzTestCheckboxFormComponent {
441470
disable(): void {
442471
this.formGroup.disable();
443472
}
473+
474+
enable(): void {
475+
this.formGroup.enable();
476+
}
444477
}
445478

446479
@Component({

components/date-picker/date-picker.component.spec.ts

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ import zh from '@angular/common/locales/zh';
66
import { ApplicationRef, Component, DebugElement, TemplateRef, ViewChild } from '@angular/core';
77
import { ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing';
88
import {
9+
FormControl,
10+
FormsModule,
11+
ReactiveFormsModule,
912
UntypedFormBuilder,
1013
UntypedFormControl,
1114
UntypedFormGroup,
12-
FormsModule,
13-
ReactiveFormsModule,
1415
Validators
1516
} from '@angular/forms';
1617
import { By } from '@angular/platform-browser';
@@ -271,22 +272,43 @@ describe('NzDatePickerComponent', () => {
271272
});
272273

273274
it('should support nzDisabled', fakeAsync(() => {
274-
// Make sure picker clear button shown up
275-
fixtureInstance.nzAllowClear = true;
275+
fixtureInstance.useSuite = 4;
276+
fixtureInstance.nzDisabled = true;
277+
fixtureInstance.nzAllowClear = true; // Make sure picker clear button shown up
276278
fixtureInstance.nzValue = new Date();
279+
fixtureInstance.control = new FormControl(new Date());
280+
fixture.detectChanges();
281+
flush();
277282

278-
fixtureInstance.nzDisabled = true;
283+
const datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;
284+
const inputElement = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;
285+
286+
expect(datePickerElement.classList).toContain('ant-picker-disabled');
287+
expect(inputElement.disabled).toBeTruthy();
288+
openPickerByClickTrigger();
289+
expect(getPickerContainer()).toBeNull();
290+
291+
fixtureInstance.control.enable();
279292
fixture.detectChanges();
280293
flush();
281294
fixture.detectChanges();
282-
expect(debugElement.query(By.css('.ant-input-disabled'))).not.toBeNull();
283-
expect(debugElement.query(By.css('.ant-picker-clear'))).toBeNull();
295+
expect(datePickerElement.classList).not.toContain('ant-picker-disabled');
296+
expect(inputElement.disabled).toBeFalsy();
297+
openPickerByClickTrigger();
298+
expect(getPickerContainer()).not.toBeNull();
284299

285-
fixtureInstance.nzDisabled = false;
300+
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);
301+
fixture.detectChanges();
286302
tick(500);
287303
fixture.detectChanges();
288-
expect(debugElement.query(By.css('.ant-input-disabled'))).toBeNull();
289-
expect(debugElement.query(By.css('.ant-picker-clear'))).not.toBeNull();
304+
fixtureInstance.control.disable();
305+
fixture.detectChanges();
306+
flush();
307+
fixture.detectChanges();
308+
expect(datePickerElement.classList).toContain('ant-picker-disabled');
309+
expect(inputElement.disabled).toBeTruthy();
310+
openPickerByClickTrigger();
311+
expect(getPickerContainer()).toBeNull();
290312
}));
291313

292314
it('should support nzInputReadOnly', fakeAsync(() => {
@@ -1199,6 +1221,11 @@ describe('NzDatePickerComponent', () => {
11991221
fixture.detectChanges();
12001222
flush(); // Wait writeValue() tobe done
12011223
fixture.detectChanges();
1224+
const datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;
1225+
const inputElement = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;
1226+
1227+
expect(datePickerElement.classList).not.toContain('ant-picker-disabled');
1228+
expect(inputElement.disabled).toBeFalsy();
12021229
expect(getPickerInput(fixture.debugElement).value!.trim()).toBe('2020-04-08');
12031230
}));
12041231

@@ -1405,7 +1432,7 @@ describe('in form', () => {
14051432
<nz-date-picker *ngSwitchCase="3" nzOpen [(ngModel)]="modelValue"></nz-date-picker>
14061433
14071434
<!-- Suite 4 -->
1408-
<nz-date-picker *ngSwitchCase="4" [formControl]="control"></nz-date-picker>
1435+
<nz-date-picker *ngSwitchCase="4" [formControl]="control" [nzDisabled]="nzDisabled"></nz-date-picker>
14091436
14101437
<!-- Suite 5 -->
14111438
<ng-container *ngSwitchCase="5">

components/date-picker/date-picker.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,7 @@ export class NzDatePickerComponent implements OnInit, OnChanges, OnDestroy, Afte
768768
setDisabledState(isDisabled: boolean): void {
769769
this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || isDisabled;
770770
this.cdr.markForCheck();
771-
this.isNzDisableFirstChange = true;
771+
this.isNzDisableFirstChange = false;
772772
}
773773

774774
// ------------------------------------------------------------------------

components/input-number/input-number.component.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ export class NzInputNumberComponent implements ControlValueAccessor, AfterViewIn
122122
private autoStepTimer?: number;
123123
private parsedValue?: string | number;
124124
private value?: number;
125+
private isNzDisableFirstChange: boolean = true;
125126
displayValue?: string | number;
126127
isFocused = false;
127128
disabled$ = new Subject<boolean>();
@@ -386,8 +387,9 @@ export class NzInputNumberComponent implements ControlValueAccessor, AfterViewIn
386387
}
387388

388389
setDisabledState(disabled: boolean): void {
389-
this.nzDisabled = disabled;
390-
this.disabled$.next(disabled);
390+
this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || disabled;
391+
this.isNzDisableFirstChange = false;
392+
this.disabled$.next(this.nzDisabled);
391393
this.cdr.markForCheck();
392394
}
393395

components/input-number/input-number.spec.ts

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { DOWN_ARROW, ENTER, TAB, UP_ARROW } from '@angular/cdk/keycodes';
22
import { ApplicationRef, Component, DebugElement, NgZone, ViewChild } from '@angular/core';
33
import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
4-
import { UntypedFormBuilder, UntypedFormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
4+
import { FormsModule, ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
55
import { By } from '@angular/platform-browser';
66
import { take } from 'rxjs/operators';
77

@@ -464,39 +464,64 @@ describe('input number', () => {
464464
describe('input number form', () => {
465465
let fixture: ComponentFixture<NzTestInputNumberFormComponent>;
466466
let testComponent: NzTestInputNumberFormComponent;
467-
let inputNumber: DebugElement;
468-
let upHandler: HTMLElement;
469467

470-
beforeEach(fakeAsync(() => {
468+
beforeEach(() => {
471469
fixture = TestBed.createComponent(NzTestInputNumberFormComponent);
470+
testComponent = fixture.componentInstance;
471+
});
472+
it('should be in pristine, untouched, and valid states and be enable initially', fakeAsync(() => {
472473
fixture.detectChanges();
473474
flush();
474-
fixture.detectChanges();
475-
testComponent = fixture.debugElement.componentInstance;
476-
inputNumber = fixture.debugElement.query(By.directive(NzInputNumberComponent));
477-
upHandler = inputNumber.nativeElement.querySelector('.ant-input-number-handler-up');
478-
}));
479-
it('should be in pristine, untouched, and valid states initially', fakeAsync(() => {
480-
flush();
475+
const inputNumber = fixture.debugElement.query(By.directive(NzInputNumberComponent));
476+
const inputElement = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;
477+
expect(inputNumber.nativeElement.classList).not.toContain('ant-input-number-disabled');
478+
expect(inputElement.disabled).toBeFalsy();
481479
expect(testComponent.formGroup.valid).toBe(true);
482480
expect(testComponent.formGroup.pristine).toBe(true);
483481
expect(testComponent.formGroup.touched).toBe(false);
484482
}));
485-
it('should set disabled work', fakeAsync(() => {
483+
it('should be disable if form disable and nzDisabled set to false initially', fakeAsync(() => {
484+
testComponent.disable();
486485
fixture.detectChanges();
487486
flush();
487+
const inputNumber = fixture.debugElement.query(By.directive(NzInputNumberComponent));
488+
const inputElement = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;
489+
expect(inputNumber.nativeElement.classList).toContain('ant-input-number-disabled');
490+
expect(inputElement.disabled).toBeTruthy();
491+
}));
492+
it('should set disabled work', fakeAsync(() => {
493+
testComponent.disabled = true;
488494
fixture.detectChanges();
495+
flush();
496+
const inputNumber = fixture.debugElement.query(By.directive(NzInputNumberComponent));
497+
const inputElement = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;
498+
const upHandler = inputNumber.nativeElement.querySelector('.ant-input-number-handler-up');
499+
expect(inputNumber.nativeElement.classList).toContain('ant-input-number-disabled');
500+
expect(inputElement.disabled).toBeTruthy();
489501
expect(testComponent.formGroup.get('inputNumber')!.value).toBe(1);
490502
dispatchFakeEvent(upHandler, 'mousedown');
491503
fixture.detectChanges();
492504
flush();
505+
expect(testComponent.formGroup.get('inputNumber')!.value).toBe(1);
506+
507+
testComponent.enable();
508+
fixture.detectChanges();
509+
flush();
510+
expect(inputNumber.nativeElement.classList).not.toContain('ant-input-number-disabled');
511+
expect(inputElement.disabled).toBeFalsy();
512+
dispatchFakeEvent(upHandler, 'mousedown');
493513
fixture.detectChanges();
514+
flush();
494515
expect(testComponent.formGroup.get('inputNumber')!.value).toBe(10);
516+
495517
testComponent.disable();
496-
dispatchFakeEvent(upHandler, 'mousedown');
497518
fixture.detectChanges();
498519
flush();
520+
expect(inputNumber.nativeElement.classList).toContain('ant-input-number-disabled');
521+
expect(inputElement.disabled).toBeTruthy();
522+
dispatchFakeEvent(upHandler, 'mousedown');
499523
fixture.detectChanges();
524+
flush();
500525
expect(testComponent.formGroup.get('inputNumber')!.value).toBe(10);
501526
}));
502527
});
@@ -598,7 +623,6 @@ describe('input number', () => {
598623
});
599624
});
600625
});
601-
602626
@Component({
603627
template: `
604628
<nz-input-number
@@ -648,12 +672,13 @@ export class NzTestReadOnlyInputNumberBasicComponent {
648672
@Component({
649673
template: `
650674
<form [formGroup]="formGroup">
651-
<nz-input-number formControlName="inputNumber" nzMax="10" nzMin="-10"></nz-input-number>
675+
<nz-input-number formControlName="inputNumber" nzMax="10" nzMin="-10" [nzDisabled]="disabled"></nz-input-number>
652676
</form>
653677
`
654678
})
655679
export class NzTestInputNumberFormComponent {
656680
formGroup: UntypedFormGroup;
681+
disabled = false;
657682

658683
constructor(private formBuilder: UntypedFormBuilder) {
659684
this.formGroup = this.formBuilder.group({
@@ -664,6 +689,10 @@ export class NzTestInputNumberFormComponent {
664689
disable(): void {
665690
this.formGroup.disable();
666691
}
692+
693+
enable(): void {
694+
this.formGroup.enable();
695+
}
667696
}
668697

669698
@Component({

components/radio/radio.component.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ export class NzRadioComponent implements ControlValueAccessor, AfterViewInit, On
8686

8787
private isNgModel = false;
8888
private destroy$ = new Subject<void>();
89+
private isNzDisableFirstChange: boolean = true;
8990
isChecked = false;
9091
name: string | null = null;
9192
isRadioButton = !!this.nzRadioButtonDirective;
@@ -118,7 +119,8 @@ export class NzRadioComponent implements ControlValueAccessor, AfterViewInit, On
118119
) {}
119120

120121
setDisabledState(disabled: boolean): void {
121-
this.nzDisabled = disabled;
122+
this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || disabled;
123+
this.isNzDisableFirstChange = false;
122124
this.cdr.markForCheck();
123125
}
124126

0 commit comments

Comments
 (0)