Skip to content

Commit

Permalink
feat(module:cascader): suooprt setting status (#7452)
Browse files Browse the repository at this point in the history
  • Loading branch information
simplejason committed May 24, 2022
1 parent 111abf3 commit e10908e
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 8 deletions.
50 changes: 43 additions & 7 deletions components/cascader/cascader.component.ts
Expand Up @@ -17,12 +17,14 @@ import {
HostListener,
Input,
NgZone,
OnChanges,
OnDestroy,
OnInit,
Optional,
Output,
QueryList,
Renderer2,
SimpleChanges,
TemplateRef,
ViewChild,
ViewChildren,
Expand All @@ -37,8 +39,15 @@ import { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/con
import { NzNoAnimationDirective } from 'ng-zorro-antd/core/no-animation';
import { DEFAULT_CASCADER_POSITIONS } from 'ng-zorro-antd/core/overlay';
import { NzDestroyService } from 'ng-zorro-antd/core/services';
import { BooleanInput, NgClassType, NgStyleInterface, NzSafeAny } from 'ng-zorro-antd/core/types';
import { InputBoolean, toArray } from 'ng-zorro-antd/core/util';
import {
BooleanInput,
NgClassInterface,
NgClassType,
NgStyleInterface,
NzSafeAny,
NzStatus
} from 'ng-zorro-antd/core/types';
import { getStatusClassNames, InputBoolean, toArray } from 'ng-zorro-antd/core/util';
import { NzCascaderI18nInterface, NzI18nService } from 'ng-zorro-antd/i18n';

import { NzCascaderOptionComponent } from './cascader-li.component';
Expand Down Expand Up @@ -210,7 +219,9 @@ const defaultDisplayRender = (labels: string[]): string => labels.join(' / ');
'[class.ant-select-rtl]': `dir ==='rtl'`
}
})
export class NzCascaderComponent implements NzCascaderComponentAsSource, OnInit, OnDestroy, ControlValueAccessor {
export class NzCascaderComponent
implements NzCascaderComponentAsSource, OnInit, OnDestroy, OnChanges, ControlValueAccessor
{
readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;
static ngAcceptInputType_nzShowInput: BooleanInput;
static ngAcceptInputType_nzShowArrow: BooleanInput;
Expand Down Expand Up @@ -256,6 +267,8 @@ export class NzCascaderComponent implements NzCascaderComponentAsSource, OnInit,
@Input() nzMenuStyle: NgStyleInterface | null = null;
@Input() nzMouseEnterDelay: number = 150; // ms
@Input() nzMouseLeaveDelay: number = 150; // ms
@Input() nzStatus?: NzStatus;

@Input() nzTriggerAction: NzCascaderTriggerType | NzCascaderTriggerType[] = ['click'] as NzCascaderTriggerType[];
@Input() nzChangeOn?: (option: NzCascaderOption, level: number) => boolean;
@Input() nzLoadData?: (node: NzCascaderOption, index: number) => PromiseLike<NzSafeAny>;
Expand All @@ -277,6 +290,10 @@ export class NzCascaderComponent implements NzCascaderComponentAsSource, OnInit,
@Output() readonly nzSelect = new EventEmitter<{ option: NzCascaderOption; index: number } | null>();
@Output() readonly nzClear = new EventEmitter<void>();

prefixCls: string = 'ant-select';
statusCls: NgClassInterface = {};
nzHasFeedback: boolean = false;

/**
* If the dropdown should show the empty content.
* `true` if there's no options.
Expand Down Expand Up @@ -359,15 +376,15 @@ export class NzCascaderComponent implements NzCascaderComponentAsSource, OnInit,
private cdr: ChangeDetectorRef,
private i18nService: NzI18nService,
private destroy$: NzDestroyService,
elementRef: ElementRef,
renderer: Renderer2,
private elementRef: ElementRef,
private renderer: Renderer2,
@Optional() private directionality: Directionality,
@Host() @Optional() public noAnimation?: NzNoAnimationDirective
) {
this.el = elementRef.nativeElement;
this.cascaderService.withComponent(this);
renderer.addClass(elementRef.nativeElement, 'ant-select');
renderer.addClass(elementRef.nativeElement, 'ant-cascader');
this.renderer.addClass(this.elementRef.nativeElement, 'ant-select');
this.renderer.addClass(this.elementRef.nativeElement, 'ant-cascader');
}

ngOnInit(): void {
Expand Down Expand Up @@ -430,6 +447,13 @@ export class NzCascaderComponent implements NzCascaderComponentAsSource, OnInit,
this.setupKeydownListener();
}

ngOnChanges(changes: SimpleChanges): void {
const { nzStatus } = changes;
if (nzStatus) {
this.setStatusStyles();
}
}

ngOnDestroy(): void {
this.clearDelayMenuTimer();
this.clearDelaySelectTimer();
Expand Down Expand Up @@ -761,6 +785,18 @@ export class NzCascaderComponent implements NzCascaderComponentAsSource, OnInit,
}
}

private setStatusStyles(): void {
// render status if nzStatus is set
this.statusCls = getStatusClassNames(this.prefixCls, this.nzStatus, this.nzHasFeedback);
Object.keys(this.statusCls).forEach(status => {
if (this.statusCls[status]) {
this.renderer.addClass(this.elementRef.nativeElement, status);
} else {
this.renderer.removeClass(this.elementRef.nativeElement, status);
}
});
}

private setLocale(): void {
this.locale = this.i18nService.getLocaleData('global');
this.cdr.markForCheck();
Expand Down
38 changes: 37 additions & 1 deletion components/cascader/cascader.spec.ts
Expand Up @@ -68,7 +68,12 @@ describe('cascader', () => {
NzCascaderModule,
NzIconTestModule
],
declarations: [NzDemoCascaderDefaultComponent, NzDemoCascaderLoadDataComponent, NzDemoCascaderRtlComponent]
declarations: [
NzDemoCascaderDefaultComponent,
NzDemoCascaderLoadDataComponent,
NzDemoCascaderRtlComponent,
NzDemoCascaderStatusComponent
]
}).compileComponents();

inject([OverlayContainer], (oc: OverlayContainer) => {
Expand Down Expand Up @@ -1786,6 +1791,29 @@ describe('cascader', () => {
expect(itemEl21.querySelector('.anticon')?.classList).toContain('anticon-left');
}));
});

describe('Status', () => {
let fixture: ComponentFixture<NzDemoCascaderStatusComponent>;
let cascader: DebugElement;

beforeEach(() => {
fixture = TestBed.createComponent(NzDemoCascaderStatusComponent);
cascader = fixture.debugElement.query(By.directive(NzCascaderComponent));
});

it('should className correct', () => {
fixture.detectChanges();
expect(cascader.nativeElement.className).toContain('ant-select-status-error');

fixture.componentInstance.status = 'warning';
fixture.detectChanges();
expect(cascader.nativeElement.className).toContain('ant-select-status-warning');

fixture.componentInstance.status = '';
fixture.detectChanges();
expect(cascader.nativeElement.className).not.toContain('ant-select-status-warning');
});
});
});

const ID_NAME_LIST = [
Expand Down Expand Up @@ -2171,3 +2199,11 @@ export class NzDemoCascaderRtlComponent {
@ViewChild(Dir) dir!: Dir;
direction = 'rtl';
}

@Component({
template: ` <nz-cascader [nzOptions]="nzOptions" [nzStatus]="status"></nz-cascader> `
})
export class NzDemoCascaderStatusComponent {
public nzOptions: any[] | null = options1;
public status = 'error';
}
14 changes: 14 additions & 0 deletions components/cascader/demo/status.md
@@ -0,0 +1,14 @@
---
order: 18
title:
zh-CN: 自定义状态
en-US: Status
---

## zh-CN

使用 `nzStatus` 为 Cascader 添加状态,可选 `error` 或者 `warning`

## en-US

Add status to Cascader with `nzStatus`, which could be `error` or `warning`.
22 changes: 22 additions & 0 deletions components/cascader/demo/status.ts
@@ -0,0 +1,22 @@
import { Component } from '@angular/core';

import { NzCascaderOption } from 'ng-zorro-antd/cascader';

@Component({
selector: 'nz-demo-cascader-status',
template: `
<nz-cascader [nzOptions]="nzOptions" nzStatus="error"></nz-cascader>
<nz-cascader [nzOptions]="nzOptions" nzStatus="warning"></nz-cascader>
`,
styles: [
`
.ant-cascader {
width: 100%;
margin-bottom: 8px;
}
`
]
})
export class NzDemoCascaderStatusComponent {
nzOptions: NzCascaderOption[] = [];
}
1 change: 1 addition & 0 deletions components/cascader/doc/index.en-US.md
Expand Up @@ -50,6 +50,7 @@ import { NzCascaderModule } from 'ng-zorro-antd/cascader';
| `[nzShowInput]` | Whether show input | `boolean` | `true` |
| `[nzShowSearch]` | Whether support search. Cannot be used with `[nzLoadData]` at the same time | `boolean\|NzShowSearchOptions` | `false` |
| `[nzSize]` | input size, one of `large` `default` `small` | `'large'\|'small'\|'default'` | `'default'` ||
| `[nzStatus]` | Set validation status | `'error' \| 'warning'` | - |
| `[nzSuffixIcon]` | The custom suffix icon | `string\|TemplateRef<void>` | - |
| `[nzValueProperty]` | the value property name of options | `string` | `'value'` |
| `(ngModelChange)` | Emit on values change | `EventEmitter<any[]>` | - |
Expand Down
1 change: 1 addition & 0 deletions components/cascader/doc/index.zh-CN.md
Expand Up @@ -51,6 +51,7 @@ import { NzCascaderModule } from 'ng-zorro-antd/cascader';
| `[nzShowInput]` | 显示输入框 | `boolean` | `true` |
| `[nzShowSearch]` | 是否支持搜索,默认情况下对 `label` 进行全匹配搜索,不能和 `[nzLoadData]` 同时使用 | `boolean\|NzShowSearchOptions` | `false` |
| `[nzSize]` | 输入框大小,可选 `large` `default` `small` | `'large'\|'small'\|'default'` | `'default'` ||
| `[nzStatus]` | 设置校验状态 | `'error' \| 'warning'` | - |
| `[nzSuffixIcon]` | 自定义的选择框后缀图标 | `string\|TemplateRef<void>` | - |
| `[nzValueProperty]` | 选项的实际值的属性名 | `string` | `'value'` |
| `(ngModelChange)` | 值发生变化时触发 | `EventEmitter<any[]>` | - |
Expand Down
2 changes: 2 additions & 0 deletions components/core/types/public-api.ts
Expand Up @@ -15,3 +15,5 @@ export * from './any';
export * from './control-value-accessor';
export * from './convert-input';
export * from './input-observable';
export * from './type';
export * from './status';
11 changes: 11 additions & 0 deletions components/core/types/status.ts
@@ -0,0 +1,11 @@
/**
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

import { tuple } from './type';

export type NzStatus = '' | 'error' | 'warning';

const ValidateStatuses = tuple('success', 'warning', 'error', 'validating', '');
export type NzValidateStatus = typeof ValidateStatuses[number];
6 changes: 6 additions & 0 deletions components/core/types/type.ts
@@ -0,0 +1,6 @@
/**
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

export const tuple = <T extends string[]>(...args: T): T => args;
1 change: 1 addition & 0 deletions components/core/util/public-api.ts
Expand Up @@ -19,3 +19,4 @@ export * from './measure-scrollbar';
export * from './ensure-in-bounds';
export * from './tick';
export * from './observable';
export * from './status-util';
20 changes: 20 additions & 0 deletions components/core/util/status-util.ts
@@ -0,0 +1,20 @@
/**
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

import { NgClassInterface, NzValidateStatus } from 'ng-zorro-antd/core/types';

export function getStatusClassNames(
prefixCls: string,
status?: NzValidateStatus,
hasFeedback?: boolean
): NgClassInterface {
return {
[`${prefixCls}-status-success`]: status === 'success',
[`${prefixCls}-status-warning`]: status === 'warning',
[`${prefixCls}-status-error`]: status === 'error',
[`${prefixCls}-status-validating`]: status === 'validating',
[`${prefixCls}-has-feedback`]: hasFeedback
};
}

0 comments on commit e10908e

Please sign in to comment.