Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(module:time-picker): support setting status #7473

Merged
merged 2 commits into from May 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion components/time-picker/demo/module
@@ -1,4 +1,5 @@
import { NzTimePickerModule } from 'ng-zorro-antd/time-picker';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzSpaceModule } from 'ng-zorro-antd/space';

export const moduleList = [ NzTimePickerModule, NzButtonModule ];
export const moduleList = [ NzTimePickerModule, NzButtonModule, NzSpaceModule ];
14 changes: 14 additions & 0 deletions components/time-picker/demo/status.md
@@ -0,0 +1,14 @@
---
order: 10
title:
zh-CN: 自定义状态
en-US: Status
---

## zh-CN

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

## en-US

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

@Component({
selector: 'nz-demo-time-picker-status',
template: `
<nz-space nzDirection="vertical">
<nz-time-picker *nzSpaceItem nzStatus="error"></nz-time-picker>
<nz-time-picker *nzSpaceItem nzStatus="warning">></nz-time-picker>
</nz-space>
`
})
export class NzDemoTimePickerStatusComponent {}
2 changes: 2 additions & 0 deletions components/time-picker/doc/index.en-US.md
Expand Up @@ -44,6 +44,8 @@ import { NzTimePickerModule } from 'ng-zorro-antd/time-picker';
| `[nzHourStep]` | interval between hours in picker | `number` | `1` | ✅ |
| `[nzMinuteStep]` | interval between minutes in picker | `number` | `1` | ✅ |
| `[nzSecondStep]` | interval between seconds in picker | `number` | `1` | ✅ |
| `[nzSize]` | width of time picker box | `'large' \| 'small' \| 'default'` | `'default'` |
| `[nzStatus]` | Set validation status | `'error' \| 'warning'` | - |
| `[nzOpen]` | whether to popup panel, double binding | `boolean` | `false` |
| `[nzPlaceHolder]` | display when there's no value | `string` | `"Select a time"` |
| `[nzPopupClassName]` | className of panel | `string` | `''` | ✅ |
Expand Down
2 changes: 2 additions & 0 deletions components/time-picker/doc/index.zh-CN.md
Expand Up @@ -45,6 +45,8 @@ import { NzTimePickerModule } from 'ng-zorro-antd/time-picker';
| `[nzHourStep]` | 小时选项间隔 | `number` | `1` | ✅ |
| `[nzMinuteStep]` | 分钟选项间隔 | `number` | `1` | ✅ |
| `[nzSecondStep]` | 秒选项间隔 | `number` | `1` | ✅ |
| `[nzSize]` | 时间选择框大小 | `'large'\|'small'\|'default'` | `'default'` |
| `[nzStatus]` | 设置校验状态 | `'error' \| 'warning'` | - |
| `[nzOpen]` | 面板是否打开,可双向绑定 | `boolean` | `false` |
| `[nzPlaceHolder]` | 没有值的时候显示的内容 | `string` | `"请选择时间"` |
| `[nzPopupClassName]` | 弹出层类名 | `string` | `''` | ✅ |
Expand Down
62 changes: 60 additions & 2 deletions components/time-picker/time-picker.component.spec.ts
@@ -1,3 +1,4 @@
import { BidiModule, Direction } from '@angular/cdk/bidi';
import { OverlayContainer } from '@angular/cdk/overlay';
import { registerLocaleData } from '@angular/common';
import zh from '@angular/common/locales/zh';
Expand All @@ -8,6 +9,7 @@ import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';

import { dispatchFakeEvent, dispatchMouseEvent, typeInElement } from 'ng-zorro-antd/core/testing';
import { NzStatus } from 'ng-zorro-antd/core/types';
import { PREFIX_CLASS } from 'ng-zorro-antd/date-picker';
import { getPickerInput, getPickerOkButton } from 'ng-zorro-antd/date-picker/testing/util';

Expand All @@ -24,9 +26,9 @@ describe('time-picker', () => {
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
imports: [NoopAnimationsModule, FormsModule, NzI18nModule, NzTimePickerModule],
imports: [BidiModule, NoopAnimationsModule, FormsModule, NzI18nModule, NzTimePickerModule],
schemas: [NO_ERRORS_SCHEMA],
declarations: [NzTestTimePickerComponent]
declarations: [NzTestTimePickerComponent, NzTestTimePickerStatusComponent, NzTestTimePickerDirComponent]
});
TestBed.compileComponents();
inject([OverlayContainer], (oc: OverlayContainer) => {
Expand Down Expand Up @@ -292,6 +294,48 @@ describe('time-picker', () => {
});
});

describe('time-picker status', () => {
let testComponent: NzTestTimePickerStatusComponent;
let fixture: ComponentFixture<NzTestTimePickerStatusComponent>;
let timeElement: DebugElement;
beforeEach(() => {
fixture = TestBed.createComponent(NzTestTimePickerStatusComponent);
testComponent = fixture.debugElement.componentInstance;
fixture.detectChanges();
timeElement = fixture.debugElement.query(By.directive(NzTimePickerComponent));
});
it('should className correct with nzStatus', () => {
fixture.detectChanges();
expect(timeElement.nativeElement.classList).toContain('ant-picker-status-error');

testComponent.status = 'warning';
fixture.detectChanges();
expect(timeElement.nativeElement.className).toContain('ant-picker-status-warning');

testComponent.status = '';
fixture.detectChanges();
expect(timeElement.nativeElement.className).not.toContain('ant-picker-status-warning');
});
});

describe('time-picker RTL', () => {
let testComponent: NzTestTimePickerDirComponent;
let fixture: ComponentFixture<NzTestTimePickerDirComponent>;
let timeElement: DebugElement;
beforeEach(() => {
fixture = TestBed.createComponent(NzTestTimePickerDirComponent);
testComponent = fixture.debugElement.componentInstance;
fixture.detectChanges();
timeElement = fixture.debugElement.query(By.directive(NzTimePickerComponent));
});
it('should className correct on dir change', () => {
expect(timeElement.nativeElement.classList).not.toContain('ant-picker-rtl');
testComponent.dir = 'rtl';
fixture.detectChanges();
expect(timeElement.nativeElement.classList).toContain('ant-picker-rtl');
});
});

function queryFromOverlay(selector: string): HTMLElement {
return overlayContainerElement.querySelector(selector) as HTMLElement;
}
Expand Down Expand Up @@ -334,3 +378,17 @@ export class NzTestTimePickerComponent {
onChange(_: Date | null): void {}
@ViewChild(NzTimePickerComponent, { static: false }) nzTimePickerComponent!: NzTimePickerComponent;
}

@Component({
template: ` <nz-time-picker [nzStatus]="status"></nz-time-picker> `
})
export class NzTestTimePickerStatusComponent {
status: NzStatus = 'error';
}

@Component({
template: ` <div [dir]="dir"><nz-time-picker></nz-time-picker></div> `
})
export class NzTestTimePickerDirComponent {
dir: Direction = 'ltr';
}
26 changes: 23 additions & 3 deletions components/time-picker/time-picker.component.ts
Expand Up @@ -34,8 +34,8 @@ import { isValid } from 'date-fns';
import { slideMotion } from 'ng-zorro-antd/core/animation';
import { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';
import { warn } from 'ng-zorro-antd/core/logger';
import { BooleanInput, NzSafeAny } from 'ng-zorro-antd/core/types';
import { InputBoolean, isNil } from 'ng-zorro-antd/core/util';
import { BooleanInput, NgClassInterface, NzSafeAny, NzStatus } from 'ng-zorro-antd/core/types';
import { getStatusClassNames, InputBoolean, isNil } from 'ng-zorro-antd/core/util';
import { DateHelperService, NzI18nInterface, NzI18nService } from 'ng-zorro-antd/i18n';

const NZ_CONFIG_MODULE_NAME: NzConfigKey = 'timePicker';
Expand Down Expand Up @@ -176,10 +176,15 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
}
] as ConnectionPositionPair[];
dir: Direction = 'ltr';
// status
prefixCls: string = 'ant-picker';
statusCls: NgClassInterface = {};
hasFeedback: boolean = false;

@ViewChild('inputElement', { static: true }) inputRef!: ElementRef<HTMLInputElement>;
@Input() nzId: string | null = null;
@Input() nzSize: string | null = null;
@Input() nzStatus?: NzStatus;
@Input() @WithConfig() nzHourStep: number = 1;
@Input() @WithConfig() nzMinuteStep: number = 1;
@Input() @WithConfig() nzSecondStep: number = 1;
Expand Down Expand Up @@ -347,7 +352,7 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
}

ngOnChanges(changes: SimpleChanges): void {
const { nzUse12Hours, nzFormat, nzDisabled, nzAutoFocus } = changes;
const { nzUse12Hours, nzFormat, nzDisabled, nzAutoFocus, nzStatus } = changes;
if (nzUse12Hours && !nzUse12Hours.previousValue && nzUse12Hours.currentValue && !nzFormat) {
this.nzFormat = 'h:mm:ss a';
}
Expand All @@ -363,6 +368,9 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
if (nzAutoFocus) {
this.updateAutoFocus();
}
if (nzStatus) {
this.setStatusStyles();
}
}

parseTimeString(str: string): void {
Expand Down Expand Up @@ -421,4 +429,16 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
disabledSeconds?.includes(value.getSeconds())
);
}

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