diff --git a/components/core/time/public-api.ts b/components/core/time/public-api.ts
index 69e5f0db587..3e1d3846c26 100644
--- a/components/core/time/public-api.ts
+++ b/components/core/time/public-api.ts
@@ -5,3 +5,4 @@
export * from './candy-date';
export * from './time';
+export { NgTimeParser as ɵNgTimeParser, TimeResult as ɵTimeResult } from './time-parser';
diff --git a/components/core/time/time-parser.spec.ts b/components/core/time/time-parser.spec.ts
new file mode 100644
index 00000000000..868b0e0ab94
--- /dev/null
+++ b/components/core/time/time-parser.spec.ts
@@ -0,0 +1,94 @@
+import { registerLocaleData } from '@angular/common';
+import zh from '@angular/common/locales/zh';
+import { Injector, LOCALE_ID } from '@angular/core';
+import { TestBed } from '@angular/core/testing';
+import { NgTimeParser, TimeResult } from './time-parser';
+
+describe('Parse time with angular format', () => {
+ let injector: Injector;
+ let localeId: string;
+ let parser: NgTimeParser;
+ let result: TimeResult | null;
+ let time: Date;
+
+ describe('default locale', () => {
+ beforeEach(() => {
+ injector = TestBed.configureTestingModule({});
+ localeId = injector.get(LOCALE_ID);
+ });
+
+ it('should parse hh:mm:ss a', () => {
+ parser = new NgTimeParser('hh:mm:ss a', localeId);
+ result = parser.getTimeResult('12:30:22 AM');
+ expect(result?.hour).toBe(12);
+ expect(result?.minute).toBe(30);
+ expect(result?.second).toBe(22);
+ expect(result?.period).toBe(0);
+
+ result = parser.getTimeResult('12:30:22 PM');
+ expect(result?.period).toBe(1);
+
+ time = parser.toDate('12:30:22 PM');
+ expect(time.getHours()).toBe(12);
+ expect(time.getMinutes()).toBe(30);
+ expect(time.getSeconds()).toBe(22);
+
+ time = parser.toDate('05:30:22 PM');
+ expect(time.getHours()).toBe(17);
+ });
+
+ it('should parse hh:mm:ss aaaaa', () => {
+ parser = new NgTimeParser('hh:mm:ss aaaaa', localeId);
+ result = parser.getTimeResult('12:30:22 a');
+ expect(result?.hour).toBe(12);
+ expect(result?.minute).toBe(30);
+ expect(result?.second).toBe(22);
+ expect(result?.period).toBe(0);
+
+ result = parser.getTimeResult('12:30:22 p');
+ expect(result?.period).toBe(1);
+ });
+
+ it('should parse mm(ss) HH', () => {
+ parser = new NgTimeParser('mm(ss) HH', localeId);
+ result = parser.getTimeResult('30(22) 12');
+ expect(result?.period).toBe(null);
+
+ time = parser.toDate('30(22) 12');
+ expect(time.getHours()).toBe(12);
+ expect(time.getMinutes()).toBe(30);
+ expect(time.getSeconds()).toBe(22);
+ });
+
+ it('should parse ss + mm', () => {
+ parser = new NgTimeParser('ss + mm', localeId);
+ time = parser.toDate('10 + 42');
+ const now = new Date();
+ expect(time.getHours()).toBe(now.getHours());
+ expect(time.getMinutes()).toBe(42);
+ expect(time.getSeconds()).toBe(10);
+ });
+ });
+
+ describe('zh locale', () => {
+ registerLocaleData(zh);
+ beforeEach(() => {
+ injector = TestBed.configureTestingModule({
+ providers: [{ provide: LOCALE_ID, useValue: 'zh-CN' }]
+ });
+ localeId = injector.get(LOCALE_ID);
+ });
+
+ it('should parse hh:mm:ss a', () => {
+ parser = new NgTimeParser('hh:mm:ss a', localeId);
+ result = parser.getTimeResult('04:45:22 上午');
+ expect(result?.hour).toBe(4);
+ expect(result?.minute).toBe(45);
+ expect(result?.second).toBe(22);
+ expect(result?.period).toBe(0);
+
+ time = parser.toDate('04:45:22 下午');
+ expect(time.getHours()).toBe(16);
+ });
+ });
+});
diff --git a/components/core/time/time-parser.ts b/components/core/time/time-parser.ts
new file mode 100644
index 00000000000..46b689d4a3b
--- /dev/null
+++ b/components/core/time/time-parser.ts
@@ -0,0 +1,143 @@
+/**
+ * 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
+ */
+
+// from https://github.com/hsuanxyz/ng-time-parser
+import { FormStyle, getLocaleDayPeriods, TranslationWidth } from '@angular/common';
+import { isNotNil } from 'ng-zorro-antd/core/util';
+
+export interface TimeResult {
+ hour: number | null;
+ minute: number | null;
+ second: number | null;
+ period: number | null;
+}
+
+export class NgTimeParser {
+ regex: RegExp = null!;
+ matchMap: { [key: string]: null | number } = {
+ hour: null,
+ minute: null,
+ second: null,
+ periodNarrow: null,
+ periodWide: null,
+ periodAbbreviated: null
+ };
+
+ constructor(private format: string, private localeId: string) {
+ this.genRegexp();
+ }
+
+ toDate(str: string): Date {
+ const result = this.getTimeResult(str);
+ const time = new Date();
+
+ if (isNotNil(result?.hour)) {
+ time.setHours(result!.hour);
+ }
+
+ if (isNotNil(result?.minute)) {
+ time.setMinutes(result!.minute);
+ }
+
+ if (isNotNil(result?.second)) {
+ time.setSeconds(result!.second);
+ }
+
+ if (result?.period === 1 && time.getHours() < 12) {
+ time.setHours(time.getHours() + 12);
+ }
+
+ return time;
+ }
+
+ getTimeResult(str: string): TimeResult | null {
+ const match = this.regex.exec(str);
+ let period = null;
+ if (match) {
+ if (isNotNil(this.matchMap.periodNarrow)) {
+ period = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Narrow).indexOf(
+ match[this.matchMap.periodNarrow + 1]
+ );
+ }
+ if (isNotNil(this.matchMap.periodWide)) {
+ period = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Wide).indexOf(match[this.matchMap.periodWide + 1]);
+ }
+ if (isNotNil(this.matchMap.periodAbbreviated)) {
+ period = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Abbreviated).indexOf(
+ match[this.matchMap.periodAbbreviated + 1]
+ );
+ }
+ return {
+ hour: isNotNil(this.matchMap.hour) ? Number.parseInt(match[this.matchMap.hour + 1], 10) : null,
+ minute: isNotNil(this.matchMap.minute) ? Number.parseInt(match[this.matchMap.minute + 1], 10) : null,
+ second: isNotNil(this.matchMap.second) ? Number.parseInt(match[this.matchMap.second + 1], 10) : null,
+ period
+ };
+ } else {
+ return null;
+ }
+ }
+
+ genRegexp(): void {
+ let regexStr = this.format.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$&');
+ const hourRegex = /h{1,2}/i;
+ const minuteRegex = /m{1,2}/;
+ const secondRegex = /s{1,2}/;
+ const periodNarrow = /aaaaa/;
+ const periodWide = /aaaa/;
+ const periodAbbreviated = /a{1,3}/;
+
+ const hourMatch = hourRegex.exec(this.format);
+ const minuteMatch = minuteRegex.exec(this.format);
+ const secondMatch = secondRegex.exec(this.format);
+ const periodNarrowMatch = periodNarrow.exec(this.format);
+ let periodWideMatch: null | RegExpExecArray = null;
+ let periodAbbreviatedMatch: null | RegExpExecArray = null;
+ if (!periodNarrowMatch) {
+ periodWideMatch = periodWide.exec(this.format);
+ }
+ if (!periodWideMatch && !periodNarrowMatch) {
+ periodAbbreviatedMatch = periodAbbreviated.exec(this.format);
+ }
+
+ const matchs = [hourMatch, minuteMatch, secondMatch, periodNarrowMatch, periodWideMatch, periodAbbreviatedMatch]
+ .filter(m => !!m)
+ .sort((a, b) => a!.index - b!.index);
+
+ matchs.forEach((match, index) => {
+ switch (match) {
+ case hourMatch:
+ this.matchMap.hour = index;
+ regexStr = regexStr.replace(hourRegex, '(\\d{1,2})');
+ break;
+ case minuteMatch:
+ this.matchMap.minute = index;
+ regexStr = regexStr.replace(minuteRegex, '(\\d{1,2})');
+ break;
+ case secondMatch:
+ this.matchMap.second = index;
+ regexStr = regexStr.replace(secondRegex, '(\\d{1,2})');
+ break;
+ case periodNarrowMatch:
+ this.matchMap.periodNarrow = index;
+ const periodsNarrow = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Narrow).join('|');
+ regexStr = regexStr.replace(periodNarrow, `(${periodsNarrow})`);
+ break;
+ case periodWideMatch:
+ this.matchMap.periodWide = index;
+ const periodsWide = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Wide).join('|');
+ regexStr = regexStr.replace(periodWide, `(${periodsWide})`);
+ break;
+ case periodAbbreviatedMatch:
+ this.matchMap.periodAbbreviated = index;
+ const periodsAbbreviated = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Abbreviated).join('|');
+ regexStr = regexStr.replace(periodAbbreviated, `(${periodsAbbreviated})`);
+ break;
+ }
+ });
+
+ this.regex = new RegExp(regexStr);
+ }
+}
diff --git a/components/date-picker/picker.component.ts b/components/date-picker/picker.component.ts
index 10ba79307ee..547fab9ba07 100644
--- a/components/date-picker/picker.component.ts
+++ b/components/date-picker/picker.component.ts
@@ -36,6 +36,7 @@ import {
} from '@angular/core';
import { slideMotion } from 'ng-zorro-antd/core/animation';
+import { ESCAPE } from '@angular/cdk/keycodes';
import { CandyDate, CompatibleValue } from 'ng-zorro-antd/core/time';
import { NgStyleInterface, NzSafeAny } from 'ng-zorro-antd/core/types';
import { DateHelperService } from 'ng-zorro-antd/i18n';
@@ -372,7 +373,7 @@ export class NzPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDe
}
onOverlayKeydown(event: KeyboardEvent): void {
- if (event.key === 'Escape') {
+ if (event.keyCode === ESCAPE) {
this.datePickerService.setValue(this.datePickerService.initialValue!);
}
}
diff --git a/components/i18n/date-helper.service.spec.ts b/components/i18n/date-helper.service.spec.ts
index df9343163f4..6cda6791ab7 100644
--- a/components/i18n/date-helper.service.spec.ts
+++ b/components/i18n/date-helper.service.spec.ts
@@ -37,8 +37,8 @@ describe('DateHelperService', () => {
});
it('should do parseTime correctly', () => {
- expect(dateHelper.parseTime('14:00')?.toTimeString().substr(0, 8)).toBe('14:00:00');
- expect(dateHelper.parseTime('4:00')?.toTimeString().substr(0, 8)).toBe('04:00:00');
+ expect(dateHelper.parseTime('14:00', 'HH:mm')?.toTimeString().substr(0, 5)).toBe('14:00');
+ expect(dateHelper.parseTime('4:00', 'H:mm')?.toTimeString().substr(0, 5)).toBe('04:00');
});
});
diff --git a/components/i18n/date-helper.service.ts b/components/i18n/date-helper.service.ts
index 9a2550fd27e..add6ad7e02b 100644
--- a/components/i18n/date-helper.service.ts
+++ b/components/i18n/date-helper.service.ts
@@ -9,7 +9,7 @@ import fnsFormat from 'date-fns/format';
import fnsGetISOWeek from 'date-fns/getISOWeek';
import fnsParse from 'date-fns/parse';
-import { WeekDayIndex } from 'ng-zorro-antd/core/time';
+import { WeekDayIndex, ɵNgTimeParser } from 'ng-zorro-antd/core/time';
import { mergeDateConfig, NzDateConfig, NZ_DATE_CONFIG } from './date-config';
import { NzI18nService } from './nz-i18n.service';
@@ -34,7 +34,7 @@ export abstract class DateHelperService {
abstract getISOWeek(date: Date): number;
abstract getFirstDayOfWeek(): WeekDayIndex;
- abstract format(date: Date, formatStr: string): string;
+ abstract format(date: Date | null, formatStr: string): string;
abstract parseDate(text: string, formatStr?: string): Date;
abstract parseTime(text: string, formatStr?: string): Date | undefined;
}
@@ -108,10 +108,8 @@ export class DateHelperByDatePipe extends DateHelperService {
return new Date(text);
}
- parseTime(text: string): Date | undefined {
- if (!text) {
- return;
- }
- return new Date(Date.parse(`1970-01-01 ${text}`));
+ parseTime(text: string, formatStr: string): Date {
+ const parser = new ɵNgTimeParser(formatStr, this.i18n.getLocaleId());
+ return parser.toDate(text);
}
}
diff --git a/components/time-picker/demo/use12-hours.ts b/components/time-picker/demo/use12-hours.ts
index 76243c29c54..3c9573124ed 100644
--- a/components/time-picker/demo/use12-hours.ts
+++ b/components/time-picker/demo/use12-hours.ts
@@ -3,8 +3,8 @@ import { Component } from '@angular/core';
@Component({
selector: 'nz-demo-time-picker-use12-hours',
template: `
-
-
+
+
`,
styles: [
`
@@ -16,4 +16,8 @@ import { Component } from '@angular/core';
})
export class NzDemoTimePickerUse12HoursComponent {
time: Date | null = null;
+
+ log(value: Date): void {
+ console.log(value);
+ }
}
diff --git a/components/time-picker/public-api.ts b/components/time-picker/public-api.ts
index 5ee40446d1e..b1a09b577a3 100644
--- a/components/time-picker/public-api.ts
+++ b/components/time-picker/public-api.ts
@@ -6,4 +6,3 @@
export * from './time-picker.component';
export * from './time-picker.module';
export * from './time-picker-panel.component';
-export * from './time-value-accessor.directive';
diff --git a/components/time-picker/time-picker-panel.component.ts b/components/time-picker/time-picker-panel.component.ts
index 140a6766130..ef58ab6cd85 100644
--- a/components/time-picker/time-picker-panel.component.ts
+++ b/components/time-picker/time-picker-panel.component.ts
@@ -27,9 +27,7 @@ import { InputBoolean, isNotNil } from 'ng-zorro-antd/core/util';
import { DateHelperService } from 'ng-zorro-antd/i18n';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
-
import { TimeHolder } from './time-holder';
-import { NzTimeValueAccessorDirective } from './time-value-accessor.directive';
function makeRange(length: number, step: number = 1, start: number = 0): number[] {
return new Array(Math.ceil(length / step)).fill(0).map((_, i) => (i + start) * step);
@@ -109,6 +107,11 @@ export type NzTimePickerUnit = 'hour' | 'minute' | 'second' | '12-hour';
{{ 'Calendar.lang.now' | nzI18n }}
+
+
+
`,
@@ -148,8 +151,6 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
secondRange!: ReadonlyArray<{ index: number; disabled: boolean }>;
use12HoursRange!: ReadonlyArray<{ index: number; value: string }>;
- @ViewChild(NzTimeValueAccessorDirective, { static: false })
- nzTimeValueAccessorDirective?: NzTimeValueAccessorDirective;
@ViewChild('hourListElement', { static: false })
hourListElement?: DebugElement;
@ViewChild('minuteListElement', { static: false }) minuteListElement?: DebugElement;
@@ -277,14 +278,6 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
return this._nzSecondStep;
}
- selectInputRange(): void {
- setTimeout(() => {
- if (this.nzTimeValueAccessorDirective) {
- this.nzTimeValueAccessorDirective.setRange();
- }
- });
- }
-
buildHours(): void {
let hourRanges = 24;
let disabledHours = this.nzDisabledHours?.();
@@ -501,6 +494,10 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
this.closePanel.emit();
}
+ onClickOk(): void {
+ this.closePanel.emit();
+ }
+
isSelectedHour(hour: { index: number; disabled: boolean }): boolean {
return hour.index === this.time.viewHours;
}
@@ -523,9 +520,9 @@ export class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit,
this.time.changes.pipe(takeUntil(this.unsubscribe$)).subscribe(() => {
this.changed();
this.touched();
+ this.scrollToTime(120);
});
this.buildTimes();
- this.selectInputRange();
setTimeout(() => {
this.scrollToTime();
this.firstScrolled = true;
diff --git a/components/time-picker/time-picker.component.spec.ts b/components/time-picker/time-picker.component.spec.ts
index 699bd593926..9f14723b7a0 100644
--- a/components/time-picker/time-picker.component.spec.ts
+++ b/components/time-picker/time-picker.component.spec.ts
@@ -5,6 +5,7 @@ import { FormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { dispatchMouseEvent } from 'ng-zorro-antd/core/testing';
+import { getPickerInput } from 'ng-zorro-antd/date-picker/testing/util';
import { NzI18nModule } from '../i18n/nz-i18n.module';
import { NzTimePickerComponent } from './time-picker.component';
import { NzTimePickerModule } from './time-picker.module';
@@ -94,7 +95,7 @@ describe('time-picker', () => {
testComponent.date = new Date('2018-11-11 11:11:11');
fixture.detectChanges();
tick(500);
- testComponent.nzTimePickerComponent.cdr.detectChanges();
+ fixture.detectChanges();
timeElement.nativeElement.querySelector('.ant-picker-clear').click();
fixture.detectChanges();
expect(testComponent.date).toBeNull();
@@ -118,6 +119,8 @@ describe('time-picker', () => {
dispatchMouseEvent(overlayContainer.getContainerElement().querySelector('.ant-picker-time-panel-cell')!, 'click');
fixture.detectChanges();
+ getPickerInput(fixture.debugElement).dispatchEvent(new KeyboardEvent('keyup', { key: 'enter' }));
+ fixture.detectChanges();
tick(500);
fixture.detectChanges();
expect(nzOnChange).toHaveBeenCalled();
diff --git a/components/time-picker/time-picker.component.ts b/components/time-picker/time-picker.component.ts
index 76dd59b3ef0..49fa30cce3c 100644
--- a/components/time-picker/time-picker.component.ts
+++ b/components/time-picker/time-picker.component.ts
@@ -22,12 +22,14 @@ import {
ViewEncapsulation
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
+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 { DateHelperService } from 'ng-zorro-antd/i18n';
const NZ_CONFIG_MODULE_NAME: NzConfigKey = 'timePicker';
@@ -42,12 +44,14 @@ const NZ_CONFIG_MODULE_NAME: NzConfigKey = 'timePicker';
#inputElement
type="text"
[size]="inputSize"
- [nzTime]="nzFormat"
[placeholder]="nzPlaceHolder || ('TimePicker.placeholder' | nzI18n)"
- [(ngModel)]="value"
+ [(ngModel)]="inputValue"
[disabled]="nzDisabled"
(focus)="onFocus(true)"
(blur)="onFocus(false)"
+ (keyup.enter)="onKeyupEnter()"
+ (keyup.escape)="onKeyupEsc()"
+ (ngModelChange)="onInputChange($event)"
/>
@@ -69,7 +73,7 @@ const NZ_CONFIG_MODULE_NAME: NzConfigKey = 'timePicker';
[cdkConnectedOverlayOffsetY]="-2"
[cdkConnectedOverlayTransformOriginOn]="'.ant-picker-dropdown'"
(detach)="close()"
- (backdropClick)="close()"
+ (backdropClick)="setCurrentValueAndClose()"
>
@@ -91,8 +95,8 @@ const NZ_CONFIG_MODULE_NAME: NzConfigKey = 'timePicker';
[nzClearText]="nzClearText"
[nzAllowEmpty]="nzAllowEmpty"
[(ngModel)]="value"
- (ngModelChange)="setValue($event)"
- (closePanel)="close()"
+ (ngModelChange)="onPanelValueChange($event)"
+ (closePanel)="setCurrentValueAndClose()"
>
@@ -123,7 +127,9 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
private _onTouched?: () => void;
isInit = false;
focused = false;
+ inputValue: string = '';
value: Date | null = null;
+ preValue: Date | null = null;
origin!: CdkOverlayOrigin;
inputSize?: number;
overlayPositions: ConnectionPositionPair[] = [
@@ -161,18 +167,29 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
@Input() @InputBoolean() nzDisabled = false;
@Input() @InputBoolean() nzAutoFocus = false;
- setValue(value: Date | null): void {
- this.value = value ? new Date(value) : null;
+ emitValue(value: Date | null): void {
+ this.setValue(value, true);
+
if (this._onChange) {
this._onChange(this.value);
}
+
if (this._onTouched) {
this._onTouched();
}
}
+ setValue(value: Date | null, syncPreValue: boolean = false): void {
+ if (syncPreValue) {
+ this.preValue = isValid(value) ? new Date(value!) : null;
+ }
+ this.value = isValid(value) ? new Date(value!) : null;
+ this.inputValue = this.dateHelper.format(value, this.nzFormat);
+ this.cdr.markForCheck();
+ }
+
open(): void {
- if (this.nzDisabled) {
+ if (this.nzDisabled || this.nzOpen) {
return;
}
this.focus();
@@ -198,7 +215,7 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
onClickClearBtn(event: MouseEvent): void {
event.stopPropagation();
- this.setValue(null);
+ this.emitValue(null);
}
onFocus(value: boolean): void {
@@ -217,11 +234,39 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
}
}
+ onKeyupEsc(): void {
+ this.setValue(this.preValue);
+ }
+
+ onKeyupEnter(): void {
+ if (this.nzOpen && isValid(this.value)) {
+ this.setCurrentValueAndClose();
+ } else if (!this.nzOpen) {
+ this.open();
+ }
+ }
+
+ onInputChange(str: string): void {
+ this.open();
+ this.parseTimeString(str);
+ }
+
+ onPanelValueChange(value: Date): void {
+ this.setValue(value);
+ this.focus();
+ }
+
+ setCurrentValueAndClose(): void {
+ this.emitValue(this.value);
+ this.close();
+ }
+
constructor(
public nzConfigService: NzConfigService,
private element: ElementRef,
private renderer: Renderer2,
- public cdr: ChangeDetectorRef
+ private cdr: ChangeDetectorRef,
+ private dateHelper: DateHelperService
) {}
ngOnInit(): void {
@@ -248,21 +293,32 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
}
}
+ parseTimeString(str: string): void {
+ const value = this.dateHelper.parseTime(str, this.nzFormat) || null;
+ if (isValid(value)) {
+ this.value = value;
+ this.cdr.markForCheck();
+ }
+ }
+
ngAfterViewInit(): void {
this.isInit = true;
this.updateAutoFocus();
}
writeValue(time: Date | null | undefined): void {
+ let result: Date | null;
+
if (time instanceof Date) {
- this.value = time;
+ result = time;
} else if (isNil(time)) {
- this.value = null;
+ result = null;
} else {
warn('Non-Date type is not recommended for time-picker, use "Date" type.');
- this.value = new Date(time);
+ result = new Date(time);
}
- this.cdr.markForCheck();
+
+ this.setValue(result, true);
}
registerOnChange(fn: (time: Date | null) => void): void {
diff --git a/components/time-picker/time-picker.module.ts b/components/time-picker/time-picker.module.ts
index 8b5d3ed07e6..c73ab3c89e8 100644
--- a/components/time-picker/time-picker.module.ts
+++ b/components/time-picker/time-picker.module.ts
@@ -7,6 +7,7 @@ import { OverlayModule } from '@angular/cdk/overlay';
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
+import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzOutletModule } from 'ng-zorro-antd/core/outlet';
import { NzOverlayModule } from 'ng-zorro-antd/core/overlay';
@@ -15,11 +16,10 @@ import { NzIconModule } from 'ng-zorro-antd/icon';
import { NzTimePickerPanelComponent } from './time-picker-panel.component';
import { NzTimePickerComponent } from './time-picker.component';
-import { NzTimeValueAccessorDirective } from './time-value-accessor.directive';
@NgModule({
- declarations: [NzTimePickerComponent, NzTimePickerPanelComponent, NzTimeValueAccessorDirective],
+ declarations: [NzTimePickerComponent, NzTimePickerPanelComponent],
exports: [NzTimePickerPanelComponent, NzTimePickerComponent],
- imports: [CommonModule, FormsModule, NzI18nModule, OverlayModule, NzIconModule, NzOverlayModule, NzOutletModule]
+ imports: [CommonModule, FormsModule, NzI18nModule, OverlayModule, NzIconModule, NzOverlayModule, NzOutletModule, NzButtonModule]
})
export class NzTimePickerModule {}
diff --git a/components/time-picker/time-value-accessor.directive.spec.ts b/components/time-picker/time-value-accessor.directive.spec.ts
index e27dea3205e..e69de29bb2d 100644
--- a/components/time-picker/time-value-accessor.directive.spec.ts
+++ b/components/time-picker/time-value-accessor.directive.spec.ts
@@ -1,78 +0,0 @@
-import { registerLocaleData } from '@angular/common';
-import zh from '@angular/common/locales/zh';
-import { Component, DebugElement, ViewChild } from '@angular/core';
-import { ComponentFixture, fakeAsync, flush, TestBed, waitForAsync } from '@angular/core/testing';
-import { FormsModule } from '@angular/forms';
-import { By } from '@angular/platform-browser';
-
-import { dispatchFakeEvent } from 'ng-zorro-antd/core/testing';
-import { NzI18nModule } from '../i18n/nz-i18n.module';
-
-import { NzTimeValueAccessorDirective } from './time-value-accessor.directive';
-
-registerLocaleData(zh);
-
-describe('input-time', () => {
- beforeEach(
- waitForAsync(() => {
- TestBed.configureTestingModule({
- imports: [FormsModule, NzI18nModule],
- declarations: [NzTimeValueAccessorDirective, NzTestTimeInputComponent]
- });
- TestBed.compileComponents();
- })
- );
-
- describe('basic input-time', () => {
- let fixture: ComponentFixture;
- let testComponent: NzTestTimeInputComponent;
- let inputElement: DebugElement;
-
- beforeEach(() => {
- fixture = TestBed.createComponent(NzTestTimeInputComponent);
- testComponent = fixture.debugElement.componentInstance;
- fixture.detectChanges();
- inputElement = fixture.debugElement.query(By.directive(NzTimeValueAccessorDirective));
- });
-
- it('should nzFormat correct', fakeAsync(() => {
- fixture.detectChanges();
- testComponent.value = new Date(0, 0, 0, 0, 0, 0);
- flush();
- fixture.detectChanges();
- flush();
- expect(inputElement.nativeElement.value).toBe('00:00:00');
- }));
-
- it('should parse correct', fakeAsync(() => {
- inputElement.nativeElement.value = '01:01:01';
- dispatchFakeEvent(inputElement.nativeElement, 'keyup');
- dispatchFakeEvent(inputElement.nativeElement, 'blur');
- fixture.detectChanges();
- flush();
- fixture.detectChanges();
- flush();
- expect(testComponent.value).toEqual(new Date(1970, 0, 1, 1, 1, 1));
- }));
-
- it('should focus work', fakeAsync(() => {
- fixture.detectChanges();
- flush();
- fixture.detectChanges();
- flush();
- testComponent.nzTimeValueAccessorDirective.setRange();
- expect(inputElement.nativeElement === document.activeElement).toBe(true);
- }));
- });
-});
-
-@Component({
- template: `
-
- `
-})
-export class NzTestTimeInputComponent {
- @ViewChild(NzTimeValueAccessorDirective, { static: false })
- nzTimeValueAccessorDirective!: NzTimeValueAccessorDirective;
- value = new Date(0, 0, 0, 0, 0, 0);
-}
diff --git a/components/time-picker/time-value-accessor.directive.ts b/components/time-picker/time-value-accessor.directive.ts
deleted file mode 100644
index 7578b4af39b..00000000000
--- a/components/time-picker/time-value-accessor.directive.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * 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 { Directive, ElementRef, HostListener, Input } from '@angular/core';
-import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
-
-import { DateHelperService } from 'ng-zorro-antd/i18n';
-
-@Directive({
- selector: 'input[nzTime]',
- exportAs: 'nzTime',
- providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: NzTimeValueAccessorDirective, multi: true }]
-})
-export class NzTimeValueAccessorDirective implements ControlValueAccessor {
- private _onChange?: (value: Date) => void;
- private _onTouch?: () => void;
- @Input() nzTime?: string;
-
- @HostListener('keyup')
- keyup(): void {
- this.changed();
- }
-
- @HostListener('blur')
- blur(): void {
- this.touched();
- }
-
- changed(): void {
- if (this._onChange) {
- const value = this.dateHelper.parseTime(this.elementRef.nativeElement.value, this.nzTime);
- this._onChange(value!);
- }
- }
-
- touched(): void {
- if (this._onTouch) {
- this._onTouch();
- }
- }
-
- setRange(): void {
- this.elementRef.nativeElement.focus();
- this.elementRef.nativeElement.setSelectionRange(0, this.elementRef.nativeElement.value.length);
- }
-
- constructor(private dateHelper: DateHelperService, private elementRef: ElementRef) {}
-
- writeValue(value: Date): void {
- this.elementRef.nativeElement.value = this.dateHelper.format(value, this.nzTime!);
- }
-
- registerOnChange(fn: (value: Date) => void): void {
- this._onChange = fn;
- }
-
- registerOnTouched(fn: () => void): void {
- this._onTouch = fn;
- }
-}