From d1505460b8d0129e53f2ec6f6d54f56ed871a6f7 Mon Sep 17 00:00:00 2001 From: Alexis Georges Date: Fri, 1 Mar 2019 17:38:12 +0100 Subject: [PATCH] feat(stark-ui): date-picker - add support for ControlValueAccessor and Validator ISSUES CLOSED: #1146 BREAKING CHANGE: stark-date-picker now integrates ControlValueAccessor and Validator: - The following Input have been changed: - **date** is now **value** - **isDisabled** is now **disabled** - The output **dateChanged** is now **dateChange** - **dateInput** Output has been added and now the date-picker Input/Output are similar to the ones of MatDatepicker component --- .../components/date-picker.component.html | 13 +- .../components/date-picker.component.spec.ts | 403 ++++++++++++------ .../components/date-picker.component.ts | 261 +++++++++++- .../modules/date-picker/date-picker.module.ts | 5 +- .../date-range-picker.component.html | 12 +- .../date-range-picker.component.spec.ts | 12 +- .../date-range-picker.module.ts | 3 +- .../components/minimap.component.spec.ts | 1 - .../demo-date-picker-page.component.html | 47 +- .../demo-date-picker-page.component.ts | 25 ++ ...demo-date-range-picker-page.component.html | 2 +- .../demo-date-range-picker-page.component.ts | 10 +- .../examples/date-picker/custom-filter.html | 6 +- .../assets/examples/date-picker/ng-model.html | 15 + .../assets/examples/date-picker/ng-model.ts | 31 ++ .../examples/date-picker/reactive-form.html | 14 + .../examples/date-picker/reactive-form.ts | 40 ++ .../assets/examples/date-picker/weekdays.html | 6 +- .../assets/examples/date-picker/weekends.html | 4 +- showcase/src/assets/translations/en.json | 2 + showcase/src/assets/translations/fr.json | 4 +- showcase/src/assets/translations/nl.json | 2 + 22 files changed, 747 insertions(+), 171 deletions(-) create mode 100644 showcase/src/assets/examples/date-picker/ng-model.html create mode 100644 showcase/src/assets/examples/date-picker/ng-model.ts create mode 100644 showcase/src/assets/examples/date-picker/reactive-form.html create mode 100644 showcase/src/assets/examples/date-picker/reactive-form.ts diff --git a/packages/stark-ui/src/modules/date-picker/components/date-picker.component.html b/packages/stark-ui/src/modules/date-picker/components/date-picker.component.html index c14171feee..ab195cc55f 100644 --- a/packages/stark-ui/src/modules/date-picker/components/date-picker.component.html +++ b/packages/stark-ui/src/modules/date-picker/components/date-picker.component.html @@ -1,17 +1,24 @@ + + +
+ +
+
diff --git a/packages/stark-ui/src/modules/date-picker/components/date-picker.component.spec.ts b/packages/stark-ui/src/modules/date-picker/components/date-picker.component.spec.ts index af6e53e4d5..066305c29e 100644 --- a/packages/stark-ui/src/modules/date-picker/components/date-picker.component.spec.ts +++ b/packages/stark-ui/src/modules/date-picker/components/date-picker.component.spec.ts @@ -1,171 +1,332 @@ -/* tslint:disable:completed-docs no-identical-functions */ +/* tslint:disable:completed-docs max-inline-declarations no-identical-functions no-big-function */ import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -import { EventEmitter } from "@angular/core"; +import { Component, ViewChild } from "@angular/core"; import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from "@angular/material/core"; import { MatDatepickerModule } from "@angular/material/datepicker"; import { MatInputModule } from "@angular/material/input"; import { MAT_MOMENT_DATE_FORMATS, MatMomentDateModule, MomentDateAdapter } from "@angular/material-moment-adapter"; -import { TranslateModule, TranslateService } from "@ngx-translate/core"; +import { TranslateModule } from "@ngx-translate/core"; import { STARK_LOGGING_SERVICE, STARK_ROUTING_SERVICE } from "@nationalbankbelgium/stark-core"; import { MockStarkLoggingService, MockStarkRoutingService } from "@nationalbankbelgium/stark-core/testing"; import { StarkDatePickerComponent } from "./date-picker.component"; +import { FormControl, FormsModule, ReactiveFormsModule } from "@angular/forms"; + +/** + * To be able to test changes to the input fields, the Date Picker component is hosted inside the TestHostWiredComponent class. + * This one uses the Output "dateChange" + */ +@Component({ + selector: `host-wired-component`, + template: ` + + ` +}) +class TestHostWiredComponent { + @ViewChild(StarkDatePickerComponent) + public datePickerComponent: StarkDatePickerComponent; + + public value: Date; + public isDisabled: boolean; + public required: boolean; + + /** + * Simulates the OnValueChanges event of the date-picker component + * To be able to test the 'Changes' output + * @param value: Date. + */ + public onValueChange(value: Date): void { + this.value = value; + } +} + +/** + * To be able to test changes to the input fields, the Date Picker component is hosted inside the TestHostNotWiredComponent class. + * This one does not use the Output "dateChange" + */ +@Component({ + selector: `host-form-control-component`, + template: ` + + ` +}) +class TestHostFormControlComponent { + @ViewChild(StarkDatePickerComponent) + public datePickerComponent: StarkDatePickerComponent; + + public value: Date; + public formControl: FormControl = new FormControl(); + public required: boolean; +} describe("DatePickerComponent", () => { - let fixture: ComponentFixture; let component: StarkDatePickerComponent; beforeEach(async(() => { return TestBed.configureTestingModule({ - declarations: [StarkDatePickerComponent], - imports: [NoopAnimationsModule, MatDatepickerModule, MatInputModule, MatMomentDateModule, TranslateModule.forRoot()], + declarations: [StarkDatePickerComponent, TestHostWiredComponent, TestHostFormControlComponent], + imports: [ + NoopAnimationsModule, + MatDatepickerModule, + MatInputModule, + MatMomentDateModule, + FormsModule, + ReactiveFormsModule, + TranslateModule.forRoot() + ], providers: [ { provide: STARK_LOGGING_SERVICE, useValue: new MockStarkLoggingService() }, { provide: STARK_ROUTING_SERVICE, useClass: MockStarkRoutingService }, { provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS }, { provide: MAT_DATE_LOCALE, useValue: "en-us" }, - { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] }, - TranslateService + { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] } ] }).compileComponents(); })); - beforeEach(() => { - fixture = TestBed.createComponent(StarkDatePickerComponent); - component = fixture.componentInstance; - - fixture.detectChanges(); - }); + describe("using formControl", () => { + let hostComponent: TestHostFormControlComponent; + let hostFixture: ComponentFixture; - describe("on initialization", () => { - it("should set internal component properties", () => { - expect(fixture).toBeDefined(); - expect(component).toBeDefined(); + beforeEach(() => { + hostFixture = TestBed.createComponent(TestHostFormControlComponent); + hostComponent = hostFixture.componentInstance; + hostFixture.detectChanges(); // trigger initial data binding - expect(component.logger).not.toBeNull(); - expect(component.logger).toBeDefined(); + component = hostComponent.datePickerComponent; }); - it("should NOT have any inputs set", () => { - expect(component.date).toBeUndefined(); - expect(component.dateFilter).toBeUndefined(); - expect(component.isDisabled).toBeUndefined(); - expect(component.label).toBeUndefined(); - expect(component.maxDate).toBeUndefined(); - expect(component.minDate).toBeUndefined(); - expect(component.minDate).toBeUndefined(); - expect(component.pickerId).toBeDefined(); - expect(component.pickerId).toEqual(""); - expect(component.pickerName).toBeDefined(); - expect(component.pickerName).toEqual(""); - expect(component.dateChanged).toBeDefined(); - expect(component.dateChanged).toEqual(new EventEmitter()); - }); - }); + describe("on initialization", () => { + it("should set internal component properties", () => { + expect(hostFixture).toBeDefined(); + expect(component).toBeDefined(); - describe("mat-datepicker properties binding", () => { - it("the id of the MatDatepicker should be pickerId", () => { - component.pickerId = "test-id"; - fixture.detectChanges(); - const input: HTMLElement = fixture.nativeElement.querySelector("#test-id"); - expect(input).not.toBeNull(); - }); + expect(component.logger).not.toBeNull(); + expect(component.logger).toBeDefined(); + }); - it("the id of the MatDatepickerInput should be pickerId + '-input'", () => { - component.pickerId = "test-id"; - fixture.detectChanges(); - const input: HTMLElement = fixture.nativeElement.querySelector("#test-id-input"); - expect(input).not.toBeNull(); + it("should NOT have any inputs set", () => { + expect(component.value).toBeUndefined(); + expect(component.dateFilter).toBeUndefined(); + expect(component.disabled).toBe(false); + expect(component.required).toBe(false); + expect(component.label).toBeUndefined(); + expect(component.maxDate).toBeUndefined(); + expect(component.minDate).toBeUndefined(); + expect(component.pickerId).toBeDefined(); + expect(component.pickerId).toEqual(""); + expect(component.pickerName).toBeDefined(); + expect(component.pickerName).toEqual(""); + expect(component.dateChange).toBeDefined(); + expect(component.dateInput).toBeDefined(); + }); }); - it("the name of the MatDatepickerInput should be pickerName", () => { - component.pickerName = "test-name"; - fixture.detectChanges(); - const input: HTMLElement = fixture.nativeElement.querySelector('[name="test-name"]'); - expect(input).not.toBeNull(); - }); + describe("mat-datepicker properties binding", () => { + it("the id of the MatDatepicker should be pickerId", () => { + component.pickerId = "test-id"; + hostFixture.detectChanges(); + const input: HTMLElement = hostFixture.nativeElement.querySelector("#test-id"); + expect(input).not.toBeNull(); + }); - it("the MatDatepickerInput should be disabled when isDisabled is true", () => { - component.isDisabled = true; - fixture.detectChanges(); - expect(component.pickerInput.disabled).toBe(true); - }); + it("the id of the MatDatepickerInput should be pickerId + '-input'", () => { + component.pickerId = "test-id"; + hostFixture.detectChanges(); + const input: HTMLElement = hostFixture.nativeElement.querySelector("#test-id-input"); + expect(input).not.toBeNull(); + }); - it("the placeholder of the MatDatepickerInput should be label", () => { - component.label = "test placeholder"; - fixture.detectChanges(); - const input: HTMLElement = fixture.nativeElement.querySelector('[placeholder="test placeholder"]'); - expect(input).not.toBeNull(); - }); + it("the name of the MatDatepickerInput should be pickerName", () => { + component.pickerName = "test-name"; + hostFixture.detectChanges(); + const input: HTMLElement = hostFixture.nativeElement.querySelector('[name="test-name"]'); + expect(input).not.toBeNull(); + }); - it("the MatDatepickerInput minDate should be min", () => { - const minDate: Date = new Date(2018, 6, 1); - component.minDate = minDate; - fixture.detectChanges(); - expect(component.pickerInput.min.toDate()).toEqual(minDate); - }); + it("the MatDatepickerInput should be disabled when isDisabled is true", () => { + hostComponent.formControl.disable(); + hostFixture.detectChanges(); + expect(component.pickerInput.disabled).toBe(true); + }); + + it("the placeholder of the MatDatepickerInput should be label", () => { + component.label = "test placeholder"; + hostFixture.detectChanges(); + const input: HTMLElement = hostFixture.nativeElement.querySelector('[placeholder="test placeholder"]'); + expect(input).not.toBeNull(); + }); + + it("the MatDatepickerInput minDate should be min", () => { + const minDate: Date = new Date(2018, 6, 1); + component.minDate = minDate; + hostFixture.detectChanges(); + expect(component.pickerInput.min.toDate()).toEqual(minDate); + }); - it("the MatDatepickerInput maxDate should be max", () => { - const maxDate: Date = new Date(2018, 6, 2); - component.maxDate = maxDate; - fixture.detectChanges(); - expect(component.pickerInput.max.toDate()).toEqual(maxDate); + it("the MatDatepickerInput maxDate should be max", () => { + const maxDate: Date = new Date(2018, 6, 2); + component.maxDate = maxDate; + hostFixture.detectChanges(); + expect(component.pickerInput.max.toDate()).toEqual(maxDate); + }); + + it("the MatDatepickerInput value should be date", () => { + const date: Date = new Date(2018, 6, 3); + hostComponent.value = date; + hostFixture.detectChanges(); + expect(component.pickerInput.value.toDate()).toEqual(date); + }); }); - it("the MatDatepickerInput value should be date", () => { - const date: Date = new Date(2018, 6, 3); - component.date = date; - fixture.detectChanges(); - expect(component.pickerInput.value.toDate()).toEqual(date); + describe("Dates filter", () => { + it("filterOnlyWeekdays() should filter week days", () => { + expect(component.filterOnlyWeekdays(new Date(2018, 6, 16))).toBe(true); + expect(component.filterOnlyWeekdays(new Date(2018, 6, 17))).toBe(true); + expect(component.filterOnlyWeekdays(new Date(2018, 6, 18))).toBe(true); + expect(component.filterOnlyWeekdays(new Date(2018, 6, 19))).toBe(true); + expect(component.filterOnlyWeekdays(new Date(2018, 6, 20))).toBe(true); + expect(component.filterOnlyWeekdays(new Date(2018, 6, 21))).toBe(false); + expect(component.filterOnlyWeekdays(new Date(2018, 6, 22))).toBe(false); + }); + + it("filterOnlyWeekends() should filter week days", () => { + expect(component.filterOnlyWeekends(new Date(2018, 6, 16))).toBe(false); + expect(component.filterOnlyWeekends(new Date(2018, 6, 17))).toBe(false); + expect(component.filterOnlyWeekends(new Date(2018, 6, 18))).toBe(false); + expect(component.filterOnlyWeekends(new Date(2018, 6, 19))).toBe(false); + expect(component.filterOnlyWeekends(new Date(2018, 6, 20))).toBe(false); + expect(component.filterOnlyWeekends(new Date(2018, 6, 21))).toBe(true); + expect(component.filterOnlyWeekends(new Date(2018, 6, 22))).toBe(true); + }); + + it("dateFilter should be filterOnlyWeekdays() when dateFilter is OnlyWeekdays", () => { + component.dateFilter = "OnlyWeekdays"; + hostFixture.detectChanges(); + expect(typeof component.dateFilter).toBe("function"); + if (typeof component.dateFilter === "function") { + expect(component.dateFilter).toBe(component.filterOnlyWeekdays); + } + }); + + it("dateFilter should be filterOnlyWeekends() when dateFilter is OnlyWeekends", () => { + component.dateFilter = "OnlyWeekends"; + expect(typeof component.dateFilter).toBe("function"); + if (typeof component.dateFilter === "function") { + expect(component.dateFilter).toBe(component.filterOnlyWeekends); + } + }); + + it("dateFilter() should be dateFilter in other cases", () => { + expect(component.dateFilter).toBeUndefined(); + const func: any = (date: Date): boolean => { + const day: number = date.getDay(); + return day === 3; + }; + component.dateFilter = func; + expect(component.dateFilter).toBe(func); + }); }); }); - describe("Dates filter", () => { - it("filterOnlyWeekdays() should filter week days", () => { - expect(component.filterOnlyWeekdays(new Date(2018, 6, 16))).toBe(true); - expect(component.filterOnlyWeekdays(new Date(2018, 6, 17))).toBe(true); - expect(component.filterOnlyWeekdays(new Date(2018, 6, 18))).toBe(true); - expect(component.filterOnlyWeekdays(new Date(2018, 6, 19))).toBe(true); - expect(component.filterOnlyWeekdays(new Date(2018, 6, 20))).toBe(true); - expect(component.filterOnlyWeekdays(new Date(2018, 6, 21))).toBe(false); - expect(component.filterOnlyWeekdays(new Date(2018, 6, 22))).toBe(false); - }); + describe("NOT using formControl", () => { + let hostComponent: TestHostWiredComponent; + let hostFixture: ComponentFixture; - it("filterOnlyWeekends() should filter week days", () => { - expect(component.filterOnlyWeekends(new Date(2018, 6, 16))).toBe(false); - expect(component.filterOnlyWeekends(new Date(2018, 6, 17))).toBe(false); - expect(component.filterOnlyWeekends(new Date(2018, 6, 18))).toBe(false); - expect(component.filterOnlyWeekends(new Date(2018, 6, 19))).toBe(false); - expect(component.filterOnlyWeekends(new Date(2018, 6, 20))).toBe(false); - expect(component.filterOnlyWeekends(new Date(2018, 6, 21))).toBe(true); - expect(component.filterOnlyWeekends(new Date(2018, 6, 22))).toBe(true); - }); + beforeEach(() => { + hostFixture = TestBed.createComponent(TestHostWiredComponent); + hostComponent = hostFixture.componentInstance; + hostFixture.detectChanges(); // trigger initial data binding - it("dateFilter should be filterOnlyWeekdays() when dateFilter is OnlyWeekdays", () => { - component.dateFilter = "OnlyWeekdays"; - fixture.detectChanges(); - expect(typeof component.dateFilter).toBe("function"); - if (typeof component.dateFilter === "function") { - expect(component.dateFilter).toBe(component.filterOnlyWeekdays); - } + component = hostComponent.datePickerComponent; }); - it("dateFilter should be filterOnlyWeekends() when dateFilter is OnlyWeekends", () => { - component.dateFilter = "OnlyWeekends"; - expect(typeof component.dateFilter).toBe("function"); - if (typeof component.dateFilter === "function") { - expect(component.dateFilter).toBe(component.filterOnlyWeekends); - } + describe("on initialization", () => { + it("should set internal component properties", () => { + expect(hostFixture).toBeDefined(); + expect(component).toBeDefined(); + + expect(component.logger).not.toBeNull(); + expect(component.logger).toBeDefined(); + }); + + it("should NOT have any inputs set", () => { + expect(component.value).toBeUndefined(); + expect(component.dateFilter).toBeUndefined(); + expect(component.disabled).toBe(false); + expect(component.required).toBe(false); + expect(component.label).toBeUndefined(); + expect(component.maxDate).toBeUndefined(); + expect(component.minDate).toBeUndefined(); + expect(component.pickerId).toBeDefined(); + expect(component.pickerId).toEqual(""); + expect(component.pickerName).toBeDefined(); + expect(component.pickerName).toEqual(""); + expect(component.dateChange).toBeDefined(); + expect(component.dateInput).toBeDefined(); + }); }); - it("dateFilter() should be dateFilter in other cases", () => { - expect(component.dateFilter).toBeUndefined(); - const func: any = (date: Date): boolean => { - const day: number = date.getDay(); - return day === 3; - }; - component.dateFilter = func; - expect(component.dateFilter).toBe(func); + describe("mat-datepicker properties binding", () => { + it("the id of the MatDatepicker should be pickerId", () => { + component.pickerId = "test-id"; + hostFixture.detectChanges(); + const input: HTMLElement = hostFixture.nativeElement.querySelector("#test-id"); + expect(input).not.toBeNull(); + }); + + it("the id of the MatDatepickerInput should be pickerId + '-input'", () => { + component.pickerId = "test-id"; + hostFixture.detectChanges(); + const input: HTMLElement = hostFixture.nativeElement.querySelector("#test-id-input"); + expect(input).not.toBeNull(); + }); + + it("the name of the MatDatepickerInput should be pickerName", () => { + component.pickerName = "test-name"; + hostFixture.detectChanges(); + const input: HTMLElement = hostFixture.nativeElement.querySelector('[name="test-name"]'); + expect(input).not.toBeNull(); + }); + + it("the MatDatepickerInput should be disabled when isDisabled is true", () => { + hostComponent.isDisabled = true; + hostFixture.detectChanges(); + expect(component.pickerInput.disabled).toBe(true); + }); + + it("the placeholder of the MatDatepickerInput should be label", () => { + component.label = "test placeholder"; + hostFixture.detectChanges(); + const input: HTMLElement = hostFixture.nativeElement.querySelector('[placeholder="test placeholder"]'); + expect(input).not.toBeNull(); + }); + + it("the MatDatepickerInput minDate should be min", () => { + const minDate: Date = new Date(2018, 6, 1); + component.minDate = minDate; + hostFixture.detectChanges(); + expect(component.pickerInput.min.toDate()).toEqual(minDate); + }); + + it("the MatDatepickerInput maxDate should be max", () => { + const maxDate: Date = new Date(2018, 6, 2); + component.maxDate = maxDate; + hostFixture.detectChanges(); + expect(component.pickerInput.max.toDate()).toEqual(maxDate); + }); + + it("the MatDatepickerInput value should be date", () => { + const date: Date = new Date(2018, 6, 3); + hostComponent.value = date; + hostFixture.detectChanges(); + expect(component.pickerInput.value.toDate()).toEqual(date); + }); }); }); }); diff --git a/packages/stark-ui/src/modules/date-picker/components/date-picker.component.ts b/packages/stark-ui/src/modules/date-picker/components/date-picker.component.ts index 3d674c1c79..4b0197b14c 100644 --- a/packages/stark-ui/src/modules/date-picker/components/date-picker.component.ts +++ b/packages/stark-ui/src/modules/date-picker/components/date-picker.component.ts @@ -1,11 +1,41 @@ -import { Component, ElementRef, EventEmitter, Inject, Input, OnInit, Output, Renderer2, ViewChild, ViewEncapsulation } from "@angular/core"; +import { + ChangeDetectorRef, + Component, + ElementRef, + EventEmitter, + Inject, + Input, + OnDestroy, + OnInit, + Output, + Renderer2, + ViewChild, + ViewEncapsulation +} from "@angular/core"; import { MatDatepicker, MatDatepickerInput, MatDatepickerInputEvent } from "@angular/material/datepicker"; import moment from "moment"; import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; import { AbstractStarkUiComponent } from "../../../common/classes/abstract-component"; +import { + AbstractControl, + ControlValueAccessor, + FormControl, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, + ValidationErrors, + Validator +} from "@angular/forms"; +import { Subscription } from "rxjs"; +import { distinctUntilChanged } from "rxjs/operators"; +import { coerceBooleanProperty } from "@angular/cdk/coercion"; export type StarkDatePickerFilter = "OnlyWeekends" | "OnlyWeekdays" | ((date: Date) => boolean) | undefined; +/** + * @ignore + */ +const _isEqual: Function = require("lodash/isEqual"); + /** * Name of the component */ @@ -21,14 +51,39 @@ const componentName: string = "stark-date-picker"; // We need to use host instead of @HostBinding: https://github.com/NationalBankBelgium/stark/issues/664 host: { class: componentName - } + }, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: StarkDatePickerComponent, + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: StarkDatePickerComponent, + multi: true + } + ] }) -export class StarkDatePickerComponent extends AbstractStarkUiComponent implements OnInit { +export class StarkDatePickerComponent extends AbstractStarkUiComponent implements OnInit, OnDestroy, ControlValueAccessor, Validator { /** * Source Date to be bound to the datepicker model */ @Input() - public date: Date; + public get value(): Date | undefined { + return this._value; + } + public set value(value: Date | undefined) { + if (!_isEqual(this._value, value)) { + this._value = value instanceof Date ? value : undefined; + const formControlValue: moment.Moment | undefined = this._value ? moment(value) : undefined; + + this.formControl.setValue(formControlValue, { + emitEvent: false + }); + } + } + private _value?: Date; /** * Filter function or a string @@ -58,7 +113,23 @@ export class StarkDatePickerComponent extends AbstractStarkUiComponent implement * Whether the datepicker is disabled */ @Input() - public isDisabled?: boolean; + public get disabled(): boolean { + return this._disabled; + } + public set disabled(value: boolean) { + const newValue: boolean = coerceBooleanProperty(value); + + if (this._disabled !== newValue) { + this._disabled = newValue; + + if (this._disabled) { + this.formControl.disable(); + } else { + this.formControl.enable(); + } + } + } + private _disabled: boolean = false; /** * Label to be displayed in the datepicker @@ -70,13 +141,27 @@ export class StarkDatePickerComponent extends AbstractStarkUiComponent implement * Maximum date of the date picker */ @Input() - public maxDate: Date; + public get maxDate(): Date { + return this._maxDate; + } + public set maxDate(value: Date) { + this._maxDate = value; + this.cdRef.detectChanges(); + } + private _maxDate: Date; /** * Minimum date of the date picker */ @Input() - public minDate: Date; + public get minDate(): Date { + return this._minDate; + } + public set minDate(value: Date) { + this._minDate = value; + this.cdRef.detectChanges(); + } + private _minDate: Date; /** * id attribute of the form field wrapping the mat-datepicker @@ -92,11 +177,34 @@ export class StarkDatePickerComponent extends AbstractStarkUiComponent implement @Input() public pickerName: string = ""; + /** + * If the dropdown is required or not. by default, the dropdown is not required + */ + @Input() + public get required(): boolean { + return this._required; + } + public set required(value: boolean) { + const newValue: boolean = coerceBooleanProperty(value); + + if (this._required !== newValue) { + this._required = newValue; + this.cdRef.detectChanges(); + } + } + private _required: boolean = false; + /** * Output that will emit a specific date whenever the selection has changed */ @Output() - public dateChanged: EventEmitter = new EventEmitter(); + public dateChange: EventEmitter = new EventEmitter(); + + /** + * Output that will emit a specific date whenever the input has changed + */ + @Output() + public dateInput: EventEmitter = new EventEmitter(); /** * Reference to the MatDatepicker embedded in this component @@ -110,16 +218,32 @@ export class StarkDatePickerComponent extends AbstractStarkUiComponent implement @ViewChild(MatDatepickerInput) public pickerInput: MatDatepickerInput; + /** + * @ignore + * @internal + */ + private formControlSubscription: Subscription; + + /** + * @ignore + * @internal + */ + private formControlStatusSubscription: Subscription; + + public formControl: FormControl = new FormControl(); + /** * Class constructor * @param logger - The logger of the application * @param renderer - Angular Renderer wrapper for DOM manipulations. * @param elementRef - Reference to the DOM element where this directive is applied to. + * @param cdRef - Reference to the change detector attached to this component */ public constructor( @Inject(STARK_LOGGING_SERVICE) public logger: StarkLoggingService, protected renderer: Renderer2, - protected elementRef: ElementRef + protected elementRef: ElementRef, + private cdRef: ChangeDetectorRef ) { super(renderer, elementRef); } @@ -128,9 +252,112 @@ export class StarkDatePickerComponent extends AbstractStarkUiComponent implement * Component lifecycle hook */ public ngOnInit(): void { + this.formControlSubscription = this.formControl.valueChanges.pipe(distinctUntilChanged()).subscribe((value?: moment.Moment) => { + this._onTouched(); + + const emitValue: Date | undefined = value ? value.toDate() : undefined; + this._onChange(emitValue); + }); + + this.formControlStatusSubscription = this.formControl.statusChanges.subscribe(() => { + this._onValidatorChange(); + }); + this.logger.debug(componentName + ": component initialized"); } + /** + * Component lifecycle hook + */ + public ngOnDestroy(): void { + if (typeof this.formControlSubscription !== "undefined") { + this.formControlSubscription.unsubscribe(); + } + if (typeof this.formControlStatusSubscription !== "undefined") { + this.formControlStatusSubscription.unsubscribe(); + } + } + + /** + * The registered callback function called when an input event occurs on the input element. + */ + private _onChange: (_: any) => void = (_: any) => { + /*noop*/ + }; + + /** + * @ignore + * The registered callback function called when a blur event occurs on the input element. + */ + public _onTouched: () => void = () => { + /*noop*/ + }; + + /** + * The registered callback function called when the validator inputs change. + */ + private _onValidatorChange: () => void = () => { + /*noop*/ + }; + + /** + * Registers a function called when the control value changes. + * + * @param fn The callback function + */ + public registerOnChange(fn: (_: any) => void): void { + this._onChange = fn; + } + + /** + * Registers a function called when the control is touched. + * + * @param fn The callback function + */ + public registerOnTouched(fn: () => void): void { + this._onTouched = fn; + } + + /** + * Sets the "disabled" property on the input element. + * + * @param isDisabled The disabled value + */ + public setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } + + /** + * Sets the "value" property on the input element. + * + * @param obj The checked value + */ + public writeValue(obj: any): void { + this.value = obj; + } + + /** + * Registers a callback function to call when the validator inputs change. + * + * @param fn - The callback function + */ + public registerOnValidatorChange(fn: () => void): void { + this._onValidatorChange = fn; + } + + /** + * Method that performs synchronous validation against the provided control. + * + * @param control - The control to validate against. + * + * @returns A map of validation errors if validation fails, + * otherwise null. + */ + public validate(control: AbstractControl): ValidationErrors | null { + // tslint:disable-next-line:no-null-keyword + return this.formControl.validator ? this.formControl.validator(control) : null; + } + /** * Wrap the dateFilter function * We use the MatMomentDateModule, so the MatDatepicker will return a moment.Moment object. To keep constitency with the old code, the end user should be able to specify a custom dateFilter accepting a Date object as a parameter @@ -170,8 +397,18 @@ export class StarkDatePickerComponent extends AbstractStarkUiComponent implement * @param event - The MatDatepickerInputEvent to re-emit */ public onDateChange(event: MatDatepickerInputEvent): void { - if (event.value) { - this.dateChanged.emit(event.value.toDate()); - } + this._onTouched(); + + const value: Date | undefined = event.value ? event.value.toDate() : undefined; + this.dateChange.emit(value); + } + + /** + * Handle the date changed on mat-datepicker and emit the dateChanged event + * @param event - The MatDatepickerInputEvent to re-emit + */ + public onDateInput(event: MatDatepickerInputEvent): void { + const value: Date | undefined = event.value ? event.value.toDate() : undefined; + this.dateInput.emit(value); } } diff --git a/packages/stark-ui/src/modules/date-picker/date-picker.module.ts b/packages/stark-ui/src/modules/date-picker/date-picker.module.ts index f12228f735..de8d643508 100644 --- a/packages/stark-ui/src/modules/date-picker/date-picker.module.ts +++ b/packages/stark-ui/src/modules/date-picker/date-picker.module.ts @@ -1,5 +1,6 @@ -import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; +import { NgModule} from "@angular/core"; +import {FormsModule, ReactiveFormsModule} from "@angular/forms"; import { MatDatepickerModule } from "@angular/material/datepicker"; import { MatInputModule } from "@angular/material/input"; import { MatMomentDateModule } from "@angular/material-moment-adapter"; @@ -8,7 +9,7 @@ import { TranslateModule } from "@ngx-translate/core"; @NgModule({ declarations: [StarkDatePickerComponent], - imports: [CommonModule, MatDatepickerModule, MatInputModule, MatMomentDateModule, TranslateModule], + imports: [CommonModule, MatDatepickerModule, MatInputModule, MatMomentDateModule, FormsModule, ReactiveFormsModule, TranslateModule], exports: [StarkDatePickerComponent] }) export class StarkDatePickerModule {} diff --git a/packages/stark-ui/src/modules/date-range-picker/components/date-range-picker.component.html b/packages/stark-ui/src/modules/date-range-picker/components/date-range-picker.component.html index a1ad63d143..d40abe8261 100644 --- a/packages/stark-ui/src/modules/date-range-picker/components/date-range-picker.component.html +++ b/packages/stark-ui/src/modules/date-range-picker/components/date-range-picker.component.html @@ -2,25 +2,25 @@ #startPicker [pickerId]="rangePickerId + '-start'" [pickerName]="rangePickerName + '-start'" - [date]="startDate" + [value]="startDate" [dateFilter]="dateFilter" - [isDisabled]="isDisabled" + [disabled]="isDisabled" [label]="startDateLabel" [minDate]="startMinDate" [maxDate]="startMaxDate" - (dateChanged)="onDateStartChanged($event)" + (dateChange)="onDateStartChanged($event)" > diff --git a/packages/stark-ui/src/modules/date-range-picker/components/date-range-picker.component.spec.ts b/packages/stark-ui/src/modules/date-range-picker/components/date-range-picker.component.spec.ts index 5b91c27849..5059d12706 100644 --- a/packages/stark-ui/src/modules/date-range-picker/components/date-range-picker.component.spec.ts +++ b/packages/stark-ui/src/modules/date-range-picker/components/date-range-picker.component.spec.ts @@ -3,12 +3,13 @@ import { EventEmitter } from "@angular/core"; import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from "@angular/material/core"; import { MAT_MOMENT_DATE_FORMATS, MomentDateAdapter } from "@angular/material-moment-adapter"; -import { TranslateModule, TranslateService } from "@ngx-translate/core"; +import { TranslateModule } from "@ngx-translate/core"; import { STARK_LOGGING_SERVICE, STARK_ROUTING_SERVICE } from "@nationalbankbelgium/stark-core"; import { MockStarkLoggingService, MockStarkRoutingService } from "@nationalbankbelgium/stark-core/testing"; import { StarkDatePickerModule } from "../../date-picker"; import { StarkDateRangePickerComponent } from "./date-range-picker.component"; import { StarkDateRangePickerEvent } from "./date-range-picker-event.intf"; +import { ReactiveFormsModule } from "@angular/forms"; describe("DateRangePickerComponent", () => { let fixture: ComponentFixture; @@ -17,14 +18,13 @@ describe("DateRangePickerComponent", () => { beforeEach(async(() => { return TestBed.configureTestingModule({ declarations: [StarkDateRangePickerComponent], - imports: [NoopAnimationsModule, StarkDatePickerModule, TranslateModule.forRoot()], + imports: [NoopAnimationsModule, StarkDatePickerModule, TranslateModule.forRoot(), ReactiveFormsModule], providers: [ { provide: STARK_LOGGING_SERVICE, useValue: new MockStarkLoggingService() }, { provide: STARK_ROUTING_SERVICE, useClass: MockStarkRoutingService }, { provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS }, { provide: MAT_DATE_LOCALE, useValue: "en-us" }, - { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] }, - TranslateService + { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] } ] }).compileComponents(); })); @@ -149,7 +149,7 @@ describe("DateRangePickerComponent", () => { component.endDate = endDate; fixture.detectChanges(); component.checkDates(); - expect(component.endDate).toBe(endDate); + expect(component.endDate).toEqual(endDate); }); it("the end date should be correctly set if after the start date is undefined", () => { @@ -158,7 +158,7 @@ describe("DateRangePickerComponent", () => { component.endDate = endDate; fixture.detectChanges(); component.checkDates(); - expect(component.endDate).toBe(endDate); + expect(component.endDate).toEqual(endDate); }); }); }); diff --git a/packages/stark-ui/src/modules/date-range-picker/date-range-picker.module.ts b/packages/stark-ui/src/modules/date-range-picker/date-range-picker.module.ts index f5dc5296f8..1cb30d96da 100644 --- a/packages/stark-ui/src/modules/date-range-picker/date-range-picker.module.ts +++ b/packages/stark-ui/src/modules/date-range-picker/date-range-picker.module.ts @@ -8,10 +8,11 @@ import { translationsEn } from "./assets/translations/en"; import { translationsFr } from "./assets/translations/fr"; import { translationsNl } from "./assets/translations/nl"; import { mergeUiTranslations } from "../../common/translations"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; @NgModule({ declarations: [StarkDateRangePickerComponent], - imports: [CommonModule, StarkDatePickerModule, TranslateModule], + imports: [CommonModule, StarkDatePickerModule, FormsModule, ReactiveFormsModule, TranslateModule], exports: [StarkDateRangePickerComponent] }) export class StarkDateRangePickerModule { diff --git a/packages/stark-ui/src/modules/minimap/components/minimap.component.spec.ts b/packages/stark-ui/src/modules/minimap/components/minimap.component.spec.ts index 73836253b1..326b5b81f7 100644 --- a/packages/stark-ui/src/modules/minimap/components/minimap.component.spec.ts +++ b/packages/stark-ui/src/modules/minimap/components/minimap.component.spec.ts @@ -143,7 +143,6 @@ describe("MinimapComponent", () => { hostFixture.detectChanges(); const dotsElement: HTMLElement | null = hostFixture.nativeElement.querySelector("stark-minimap .stark-minimap-dots"); - console.log(dotsElement); expect(dotsElement).toBeNull("compact view should not have dots"); }); }); diff --git a/showcase/src/app/demo-ui/pages/date-picker/demo-date-picker-page.component.html b/showcase/src/app/demo-ui/pages/date-picker/demo-date-picker-page.component.html index bbf37770d5..eec5a4534a 100644 --- a/showcase/src/app/demo-ui/pages/date-picker/demo-date-picker-page.component.html +++ b/showcase/src/app/demo-ui/pages/date-picker/demo-date-picker-page.component.html @@ -1,16 +1,51 @@

SHOWCASE.DEMO.DATE_PICKER.TITLE

SHOWCASE.DEMO.SHARED.EXAMPLE_VIEWER_LIST

+ + + +
+ + disabled + +
+
+ + + +
+ + disabled + +
+
+ @@ -18,12 +53,12 @@

SHOWCASE.DEMO.SHARED.EXAMPLE_VIEWER_LIST

@@ -35,12 +70,12 @@

SHOWCASE.DEMO.SHARED.EXAMPLE_VIEWER_LIST

diff --git a/showcase/src/app/demo-ui/pages/date-picker/demo-date-picker-page.component.ts b/showcase/src/app/demo-ui/pages/date-picker/demo-date-picker-page.component.ts index 511617c9e5..3f93ce9ac5 100644 --- a/showcase/src/app/demo-ui/pages/date-picker/demo-date-picker-page.component.ts +++ b/showcase/src/app/demo-ui/pages/date-picker/demo-date-picker-page.component.ts @@ -2,6 +2,8 @@ import { Component, Inject, OnInit } from "@angular/core"; import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; import { StarkDatePickerFilter } from "@nationalbankbelgium/stark-ui"; import { ReferenceLink } from "../../../shared/components"; +import { FormControl } from "@angular/forms"; +import { Subscription } from "rxjs"; @Component({ selector: "demo-date-picker", @@ -9,11 +11,16 @@ import { ReferenceLink } from "../../../shared/components"; }) export class DemoDatePickerPageComponent implements OnInit { public currentDate: Date; + public ngModelDate: Date; + public disabled: boolean; + public formControl: FormControl; public minDate: Date; public maxDate: Date; public customDateFilter: StarkDatePickerFilter; public referenceList: ReferenceLink[]; + public subscription: Subscription; + public constructor(@Inject(STARK_LOGGING_SERVICE) public logger: StarkLoggingService) {} /** @@ -21,9 +28,15 @@ export class DemoDatePickerPageComponent implements OnInit { */ public ngOnInit(): void { this.currentDate = new Date(); + this.ngModelDate = new Date(); this.minDate = new Date(); this.maxDate = new Date(); this.maxDate.setMonth(this.maxDate.getMonth() + 6); + this.formControl = new FormControl(new Date()); + + this.subscription = this.formControl.valueChanges.subscribe((date: Date) => { + this.onDateChanged(date); + }); this.customDateFilter = (date: Date): boolean => { const day: number = date.getDay(); @@ -41,4 +54,16 @@ export class DemoDatePickerPageComponent implements OnInit { public onDateChanged(date: Date): void { this.logger.debug(date); } + + public onDateNgModelChanged(): void { + this.logger.debug("ngModel: ", this.ngModelDate); + } + + public toggleDisabledReactiveFormControl(formControl: FormControl): void { + if (formControl.disabled) { + formControl.enable(); + } else { + formControl.disable(); + } + } } diff --git a/showcase/src/app/demo-ui/pages/date-range-picker/demo-date-range-picker-page.component.html b/showcase/src/app/demo-ui/pages/date-range-picker/demo-date-range-picker-page.component.html index 4ae6eec244..f8558e0f13 100644 --- a/showcase/src/app/demo-ui/pages/date-range-picker/demo-date-range-picker-page.component.html +++ b/showcase/src/app/demo-ui/pages/date-range-picker/demo-date-range-picker-page.component.html @@ -14,7 +14,7 @@

SHOWCASE.DEMO.SHARED.EXAMPLE_VIEWER_LIST

endDateLabel="STARK.DATE_RANGE_PICKER.TO" [startMinDate]="minDate" [startMaxDate]="maxDate" - [endMinDate]="minDate" + [endMinDate]="startDate || minDate" [endMaxDate]="maxDate" (dateRangeChanged)="onDateChanged($event)" > diff --git a/showcase/src/app/demo-ui/pages/date-range-picker/demo-date-range-picker-page.component.ts b/showcase/src/app/demo-ui/pages/date-range-picker/demo-date-range-picker-page.component.ts index d51a48f95d..bb152150ed 100644 --- a/showcase/src/app/demo-ui/pages/date-range-picker/demo-date-range-picker-page.component.ts +++ b/showcase/src/app/demo-ui/pages/date-range-picker/demo-date-range-picker-page.component.ts @@ -2,6 +2,7 @@ import { Component, Inject, OnInit } from "@angular/core"; import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; import { StarkDatePickerFilter } from "@nationalbankbelgium/stark-ui"; import { ReferenceLink } from "../../../shared/components"; +import {StarkDateRangePickerEvent} from "@nationalbankbelgium/stark-ui/src/modules/date-range-picker/components/date-range-picker-event.intf"; @Component({ selector: "demo-date-range-picker", @@ -9,8 +10,8 @@ import { ReferenceLink } from "../../../shared/components"; }) export class DemoDateRangePickerPageComponent implements OnInit { public isDisabled: boolean; - public startDate: Date; - public endDate: Date; + public startDate?: Date; + public endDate?: Date; public minDate: Date; public maxDate: Date; public customDateFilter: StarkDatePickerFilter; @@ -39,7 +40,10 @@ export class DemoDateRangePickerPageComponent implements OnInit { ]; } - public onDateChanged(event: Object): void { + public onDateChanged(event: StarkDateRangePickerEvent): void { this.logger.debug(event); + + this.startDate = event.startDate; + this.endDate = event.endDate; } } diff --git a/showcase/src/assets/examples/date-picker/custom-filter.html b/showcase/src/assets/examples/date-picker/custom-filter.html index d1a50e86a0..cbe52b67d5 100644 --- a/showcase/src/assets/examples/date-picker/custom-filter.html +++ b/showcase/src/assets/examples/date-picker/custom-filter.html @@ -1,11 +1,11 @@ diff --git a/showcase/src/assets/examples/date-picker/ng-model.html b/showcase/src/assets/examples/date-picker/ng-model.html new file mode 100644 index 0000000000..d2021d26e4 --- /dev/null +++ b/showcase/src/assets/examples/date-picker/ng-model.html @@ -0,0 +1,15 @@ + +
+ + disabled + +
diff --git a/showcase/src/assets/examples/date-picker/ng-model.ts b/showcase/src/assets/examples/date-picker/ng-model.ts new file mode 100644 index 0000000000..cc448d373e --- /dev/null +++ b/showcase/src/assets/examples/date-picker/ng-model.ts @@ -0,0 +1,31 @@ +import { Component, Inject, OnDestroy, OnInit } from "@angular/core"; +import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; +import { Subscription } from "rxjs"; + +@Component({ + selector: "demo-date-picker", + templateUrl: "./demo-date-picker.component.html" +}) +export class DemoDatePickerComponent implements OnInit, OnDestroy { + public date?: Date; + public minDate: Date; + public maxDate: Date; + public disabled: boolean; + + private subscription: Subscription; + + public constructor(@Inject(STARK_LOGGING_SERVICE) public logger: StarkLoggingService) {} + + public ngOnInit(): void { + this.minDate = new Date("07-01-2017"); + this.maxDate = new Date("07-20-2017"); + } + + public ngOnDestroy(): void { + this.subscription.unsubscribe(); + } + + public onDateChanged(): void { + this.logger.debug("ngModel: ", this.date); + } +} diff --git a/showcase/src/assets/examples/date-picker/reactive-form.html b/showcase/src/assets/examples/date-picker/reactive-form.html new file mode 100644 index 0000000000..58b86137fb --- /dev/null +++ b/showcase/src/assets/examples/date-picker/reactive-form.html @@ -0,0 +1,14 @@ + + +
+ + isDisabled + +
diff --git a/showcase/src/assets/examples/date-picker/reactive-form.ts b/showcase/src/assets/examples/date-picker/reactive-form.ts new file mode 100644 index 0000000000..1753fa9f48 --- /dev/null +++ b/showcase/src/assets/examples/date-picker/reactive-form.ts @@ -0,0 +1,40 @@ +import { Component, Inject, OnDestroy, OnInit } from "@angular/core"; +import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; +import { FormControl } from "@angular/forms"; +import { Subscription } from "rxjs"; + +@Component({ + selector: "demo-date-picker", + templateUrl: "./demo-date-picker.component.html" +}) +export class DemoDatePickerComponent implements OnInit, OnDestroy { + public formControl: FormControl; + public minDate: Date; + public maxDate: Date; + + private subscription: Subscription; + + public constructor(@Inject(STARK_LOGGING_SERVICE) public logger: StarkLoggingService) {} + + public ngOnInit(): void { + this.formControl = new FormControl(moment(new Date())); + this.minDate = new Date("07-01-2017"); + this.maxDate = new Date("07-20-2017"); + + this.subscription = this.formControl.valueChanges.subscribe((value?: Date) => { + this.logger.debug(value); + }); + } + + public ngOnDestroy(): void { + this.subscription.unsubscribe(); + } + + public toggleDisabledReactiveFormControl(formControl: FormControl): void { + if (formControl.disabled) { + formControl.enable(); + } else { + formControl.disable(); + } + } +} diff --git a/showcase/src/assets/examples/date-picker/weekdays.html b/showcase/src/assets/examples/date-picker/weekdays.html index f80367e4e1..0efd27108c 100644 --- a/showcase/src/assets/examples/date-picker/weekdays.html +++ b/showcase/src/assets/examples/date-picker/weekdays.html @@ -1,11 +1,11 @@ diff --git a/showcase/src/assets/examples/date-picker/weekends.html b/showcase/src/assets/examples/date-picker/weekends.html index 2db0e1764d..f6101a32e0 100644 --- a/showcase/src/assets/examples/date-picker/weekends.html +++ b/showcase/src/assets/examples/date-picker/weekends.html @@ -1,11 +1,11 @@ diff --git a/showcase/src/assets/translations/en.json b/showcase/src/assets/translations/en.json index 237a251231..b10f74ef40 100644 --- a/showcase/src/assets/translations/en.json +++ b/showcase/src/assets/translations/en.json @@ -43,9 +43,11 @@ }, "DATE_PICKER": { "CUSTOM_FILTER": "Date Picker - Custom Filter", + "NG_MODEL": "Date Picker - Using NgModel", "ONLY_WEEKDAYS": "Date Picker - Only weekdays", "ONLY_WEEKENDS": "Date Picker - Only weekends", "PLACEHOLDER": "Choose a date", + "REACTIVE_FORM": "Date Picker - Using Reactive form", "TITLE": "Date picker" }, "DATE_RANGE_PICKER": { diff --git a/showcase/src/assets/translations/fr.json b/showcase/src/assets/translations/fr.json index 9591713577..a670f1fdda 100644 --- a/showcase/src/assets/translations/fr.json +++ b/showcase/src/assets/translations/fr.json @@ -34,7 +34,7 @@ "CLOSED": "Fermé", "CUSTOM_ICON": "Icône custom", "DEFAULT_ICON": "Icône par défaut", - "HTML_CONTENT": "N'impoerte quel contenu HTML", + "HTML_CONTENT": "N'importe quel contenu HTML", "OPEN": "Ouvert", "TITLE": "Collapsible", "TITLE_0": "Titre du collapsible avec icône par défaut", @@ -43,9 +43,11 @@ }, "DATE_PICKER": { "CUSTOM_FILTER": "Date Picker - Filtre sur mesure", + "NG_MODEL": "Date Picker - Utilisant NgModel", "ONLY_WEEKDAYS": "Date Picker - Seulement les jours de semaine", "ONLY_WEEKENDS": "Date Picker - Seulement les jours de weekend", "PLACEHOLDER": "Choisir une date", + "REACTIVE_FORM": "Date Picker - Utilisant Reactive form", "TITLE": "Date picker" }, "DATE_RANGE_PICKER": { diff --git a/showcase/src/assets/translations/nl.json b/showcase/src/assets/translations/nl.json index 0d4d47a7d7..aab5de0466 100644 --- a/showcase/src/assets/translations/nl.json +++ b/showcase/src/assets/translations/nl.json @@ -43,9 +43,11 @@ }, "DATE_PICKER": { "CUSTOM_FILTER": "Date Picker - Aangepaste filter", + "NG_MODEL": "Date Picker - NgModel gebruiken", "ONLY_WEEKDAYS": "Date Picker - Alleen weekdagen", "ONLY_WEEKENDS": "Date Picker - Alleen weekenden", "PLACEHOLDER": "Datum kiezen", + "REACTIVE_FORM": "Date Picker - Reactive form gebruiken", "TITLE": "Date picker" }, "DATE_RANGE_PICKER": {