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

fix(module:date-picker): support changing language at runtime #1768

Merged
merged 1 commit into from
Jul 2, 2018
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 37 additions & 8 deletions components/date-picker/abstract-picker.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ import {
EventEmitter,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
SimpleChanges,
ViewChild
} from '@angular/core';
import { ControlValueAccessor } from '@angular/forms';

import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { InputBoolean } from '../core/util/convert';
import { NzDatePickerI18nInterface } from '../i18n/nz-i18n.interface';
import { NzI18nService } from '../i18n/nz-i18n.service';
Expand All @@ -20,7 +23,7 @@ const POPUP_STYLE_PATCH = { 'position': 'relative' }; // Aim to override antd's
/**
* The base picker for all common APIs
*/
export abstract class AbstractPickerComponent implements OnInit, OnChanges, ControlValueAccessor {
export abstract class AbstractPickerComponent implements OnInit, OnChanges, OnDestroy, ControlValueAccessor {
// --- Common API
@Input() @InputBoolean() nzAllowClear: boolean = true;
@Input() @InputBoolean() nzAutoFocus: boolean = false;
Expand Down Expand Up @@ -52,28 +55,42 @@ export abstract class AbstractPickerComponent implements OnInit, OnChanges, Cont
this.nzValue = this.isRange ? [] : null;
}

protected destroyed$: Subject<void> = new Subject();
protected isCustomPlaceHolder: boolean = false;

constructor(protected i18n: NzI18nService) {
}

ngOnInit(): void {
// Default locale (NOTE: Place here to assign default value due to the i18n'locale may change before ngOnInit)
// Subscribe the every locale change if the nzLocale is not handled by user
if (!this.nzLocale) {
this.nzLocale = this.i18n.getLocaleData('DatePicker', {});
this.i18n.localeChange
.pipe(takeUntil(this.destroyed$))
.subscribe(() => this.setLocale());
}

// Default value
this.initValue();

// Default placeholder
if (!this.nzPlaceHolder) {
this.nzPlaceHolder = this.isRange ? this.nzLocale.lang.rangePlaceholder : this.nzLocale.lang.placeholder;
}
}

ngOnChanges(changes: SimpleChanges): void {
if (changes.nzPopupStyle) { // Always assign the popup style patch
this.nzPopupStyle = this.nzPopupStyle ? { ...this.nzPopupStyle, ...POPUP_STYLE_PATCH } : POPUP_STYLE_PATCH;
}

// Mark as customized placeholder by user once nzPlaceHolder assigned at the first time
if (changes.nzPlaceHolder && changes.nzPlaceHolder.firstChange && typeof this.nzPlaceHolder !== 'undefined') {
this.isCustomPlaceHolder = true;
}

if (changes.nzLocale) { // The nzLocale is currently handled by user
this.setDefaultPlaceHolder();
}
}

ngOnDestroy(): void {
this.destroyed$.next();
this.destroyed$.complete();
}

closeOverlay(): void {
Expand Down Expand Up @@ -138,6 +155,18 @@ export abstract class AbstractPickerComponent implements OnInit, OnChanges, Cont
// | Internal methods
// ------------------------------------------------------------------------

// Reload locale from i18n with side effects
private setLocale(): void {
this.nzLocale = this.i18n.getLocaleData('DatePicker', {});
this.setDefaultPlaceHolder();
}

private setDefaultPlaceHolder(): void {
if (!this.isCustomPlaceHolder && this.nzLocale) {
this.nzPlaceHolder = this.isRange ? this.nzLocale.lang.rangePlaceholder : this.nzLocale.lang.placeholder;
}
}

private formatDate(date: CandyDate): string {
return date ? this.i18n.formatDateCompatible(date.nativeDate, this.nzFormat) : '';
}
Expand Down
24 changes: 22 additions & 2 deletions components/date-picker/date-picker.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import * as isSameDay from 'date-fns/is_same_day';

import { dispatchKeyboardEvent, dispatchMouseEvent } from '../core/testing';
import en_US from '../i18n/languages/en_US';
import { NzI18nModule } from '../i18n/nz-i18n.module';
import { NzI18nService } from '../i18n/nz-i18n.service';
import { NzDatePickerModule } from './date-picker.module';
import { PickerResultSingle } from './standard-types';

Expand All @@ -21,10 +24,11 @@ describe('NzDatePickerComponent', () => {
let debugElement: DebugElement;
let overlayContainer: OverlayContainer;
let overlayContainerElement: HTMLElement;
let i18nService: NzI18nService;

beforeEach(fakeAsync(() => {
TestBed.configureTestingModule({
imports : [ FormsModule, NoopAnimationsModule, NzDatePickerModule ],
imports : [ FormsModule, NoopAnimationsModule, NzDatePickerModule, NzI18nModule ],
providers : [],
declarations: [
NzTestDatePickerComponent
Expand All @@ -40,9 +44,10 @@ describe('NzDatePickerComponent', () => {
debugElement = fixture.debugElement;
});

beforeEach(inject([ OverlayContainer ], (oc: OverlayContainer) => {
beforeEach(inject([ OverlayContainer, NzI18nService ], (oc: OverlayContainer, i18n: NzI18nService) => {
overlayContainer = oc;
overlayContainerElement = oc.getContainerElement();
i18nService = i18n;
}));

afterEach(() => {
Expand All @@ -67,6 +72,21 @@ describe('NzDatePickerComponent', () => {
expect(getPickerContainer()).toBeNull();
}));

it('should support changing language at runtime', fakeAsync(() => {
fixture.detectChanges();
expect(getPickerTrigger().placeholder).toBe('请选择日期');
i18nService.setLocale(en_US);
fixture.detectChanges();
expect(getPickerTrigger().placeholder).toBe('Select date');

dispatchMouseEvent(getPickerTrigger(), 'click');
fixture.detectChanges();
tick(500);
fixture.detectChanges();
expect((queryFromOverlay('.ant-calendar-date-input-wrap input.ant-calendar-input') as HTMLInputElement).placeholder).toBe('Select date');
expect(queryFromOverlay('.ant-calendar-table .ant-calendar-column-header-inner').textContent).toContain('Su');
}));

/* Issue https://github.com/NG-ZORRO/ng-zorro-antd/issues/1539 */
it('should be openable after closed by "Escape" key', fakeAsync(() => {
fixture.detectChanges();
Expand Down
11 changes: 11 additions & 0 deletions components/date-picker/demo/basic.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Component } from '@angular/core';
import * as getISOWeek from 'date-fns/get_iso_week';
import { en_US, zh_CN, NzI18nService } from 'ng-zorro-antd';

@Component({
selector: 'nz-demo-date-picker-basic',
Expand All @@ -11,6 +12,8 @@ import * as getISOWeek from 'date-fns/get_iso_week';
<nz-range-picker [(ngModel)]="dateRange" (ngModelChange)="onChange($event)" nzShowTime></nz-range-picker>
<br>
<nz-week-picker [(ngModel)]="date" (ngModelChange)="getWeek($event)" nzPlaceHolder="Select week"></nz-week-picker>
<br>
<button nz-button nzType="default" (click)="changeLanguage()">Switch language for all pickers</button>
`,
styles : [ `
nz-date-picker, nz-month-picker, nz-range-picker, nz-week-picker {
Expand All @@ -22,6 +25,9 @@ import * as getISOWeek from 'date-fns/get_iso_week';
export class NzDemoDatePickerBasicComponent {
date = null; // new Date();
dateRange = []; // [ new Date(), addDays(new Date(), 3) ];
isEnglish = false;

constructor(private i18n: NzI18nService) {}

onChange(result: Date): void {
console.log('onChange: ', result);
Expand All @@ -30,4 +36,9 @@ export class NzDemoDatePickerBasicComponent {
getWeek(result: Date): void {
console.log('week: ', getISOWeek(result));
}

changeLanguage(): void {
this.i18n.setLocale(this.isEnglish ? zh_CN : en_US);
this.isEnglish = !this.isEnglish;
}
}