From e9593d97c74f9a4d4fa12a3fe47afd5a12f93761 Mon Sep 17 00:00:00 2001 From: kukjevov Date: Wed, 4 Jan 2023 12:07:33 +0100 Subject: [PATCH] INT: added previously destroyed date time input handler --- changelog.md | 19 + .../datePickerInput.directive.ts | 33 + .../dateTimeInputHandler.directive.ts | 383 ++++++++++++ .../dateTimePickerInput.directive.ts | 25 + src/directives/index.ts | 4 + src/directives/withNow/withNow.directive.ts | 47 ++ .../withToday/withToday.directive.ts | 12 +- .../inputDateTime/inputDateTime.component.css | 9 - .../inputDateTime.component.html | 10 - .../inputDateTime/inputDateTime.component.ts | 577 ------------------ .../simpleInputDateTime.component.css | 9 - .../simpleInputDateTime.component.html | 9 - .../simpleInputDateTime.component.ts | 430 ------------- src/misc/utils.ts | 85 ++- .../directives/dateTime/dateTime.directive.ts | 56 +- 15 files changed, 642 insertions(+), 1066 deletions(-) create mode 100644 src/directives/datePickerInput/datePickerInput.directive.ts create mode 100644 src/directives/dateTimeInputHandler/dateTimeInputHandler.directive.ts create mode 100644 src/directives/dateTimePickerInput/dateTimePickerInput.directive.ts create mode 100644 src/directives/withNow/withNow.directive.ts delete mode 100644 src/legacy/selector/components/inputDateTime/inputDateTime.component.css delete mode 100644 src/legacy/selector/components/inputDateTime/inputDateTime.component.html delete mode 100644 src/legacy/selector/components/inputDateTime/inputDateTime.component.ts delete mode 100644 src/legacy/selector/components/simpleInputDateTime/simpleInputDateTime.component.css delete mode 100644 src/legacy/selector/components/simpleInputDateTime/simpleInputDateTime.component.html delete mode 100644 src/legacy/selector/components/simpleInputDateTime/simpleInputDateTime.component.ts diff --git a/changelog.md b/changelog.md index 953ed9d..366f9f4 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,24 @@ # Changelog +## Version 6.1.0 (2023-01-04) + +### Bug Fixes + +- fixed `WithTodaySADirective` + - now correctly sets value of date time to start of a current day + +### Features + +- new `WithNowSADirective` directive, that sets current date and time as day and time for empty date time on focus +- new `DateTimeInputHandlerSADirective` directive, that adds handler for date time input, which allows navigation using keyboard and checking restriction of value +- new `DatePickerInputSADirective` directive, that combines date picker with date input +- new `DateTimePickerInputSADirective` directive, that combines date time picker with date time input +- new `parseRawInput` function, that parses raw value into internal value and value +- new `getInternalValue` function, gets internal value and fix lowest time difference +- updated `DateTimeSADirective` directive + - **new properties** + - `customFormatChanges` occurs when there are changes in custom format value + ## Version 6.0.0 (2022-12-23) ### Features diff --git a/src/directives/datePickerInput/datePickerInput.directive.ts b/src/directives/datePickerInput/datePickerInput.directive.ts new file mode 100644 index 0000000..152b4f2 --- /dev/null +++ b/src/directives/datePickerInput/datePickerInput.directive.ts @@ -0,0 +1,33 @@ +import {Directive} from '@angular/core'; + +import {DateTimeInputSADirective, DateTimePickerSADirective} from '../../modules'; +import {DateTimeInputHandlerSADirective} from '../dateTimeInputHandler/dateTimeInputHandler.directive'; + +/** + * Directive that combines date picker with date input + */ +@Directive( +{ + selector: 'input[dateTime][datePickerInput]', + standalone: true, + hostDirectives: + [ + { + directive: DateTimePickerSADirective, + inputs: + [ + 'withPickerOptions', + 'pickerOptions', + ] + }, + { + directive: DateTimeInputSADirective, + }, + { + directive: DateTimeInputHandlerSADirective, + }, + ], +}) +export class DatePickerInputSADirective +{ +} \ No newline at end of file diff --git a/src/directives/dateTimeInputHandler/dateTimeInputHandler.directive.ts b/src/directives/dateTimeInputHandler/dateTimeInputHandler.directive.ts new file mode 100644 index 0000000..a60a870 --- /dev/null +++ b/src/directives/dateTimeInputHandler/dateTimeInputHandler.directive.ts @@ -0,0 +1,383 @@ +import {Directive, Inject, OnDestroy, OnInit, Optional} from '@angular/core'; +import {Action1, BindThis} from '@jscrpt/common'; +import {Subscription} from 'rxjs'; + +import {DateTimeInput} from '../../interfaces'; +import {DATE_API, DATE_TIME_INPUT} from '../../misc/tokens'; +import {DateTimeObjectValue} from '../../misc/types'; +import {parseDateTime, parseRawInput} from '../../misc/utils'; +import {DateTimePickerSADirective, DateTimeSADirective} from '../../modules'; +import {DateApi, DateApiObject, DatePositionParser, DatePositionParserService, DateValueProvider} from '../../services'; + +/** + * Directive that adds handler for date time input, which allows navigation using keyboard and checking restriction of value + */ +@Directive( +{ + selector: '[dateTime][withHandler]', + standalone: true, +}) +export class DateTimeInputHandlerSADirective implements OnInit, OnDestroy +{ + //######################### protected properties ######################### + + /** + * Subscriptions created during initialization + */ + protected initSubscriptions: Subscription = new Subscription(); + + /** + * Instance of parser created for specific format + */ + protected parser: DatePositionParser; + + /** + * Gets input element as html input + */ + protected get inputElement(): HTMLInputElement + { + if(this.input.element.nodeName == 'INPUT') + { + return this.input.element as HTMLInputElement; + } + + throw new Error('You cant use DateTimeInputHandlerSADirective without input element!'); + } + + //######################### constructor ######################### + constructor(@Inject(DATE_TIME_INPUT) protected input: DateTimeInput, + @Inject(DATE_API) protected dateApi: DateApi, + protected dateTimeData: DateTimeSADirective, + protected parserSvc: DatePositionParserService, + protected valueProvider: DateValueProvider, + @Optional() protected picker?: DateTimePickerSADirective,) + { + this.parser = parserSvc.createParser(this.dateTimeData.customFormat); + this.initSubscriptions.add(this.dateTimeData.customFormatChanges.subscribe(() => this.parser = parserSvc.createParser(this.dateTimeData.customFormat))); + } + + //######################### public methods - implementation of OnInit ######################### + + /** + * Initialize component + */ + public ngOnInit(): void + { + this.input.element.addEventListener('keydown', this.handleKeyboard); + this.input.element.addEventListener('keypress', this.handleKeypress); + this.input.element.addEventListener('select', this.handleSelect); + this.input.element.addEventListener('click', this.handleClick); + } + + //######################### public methods - implementation of OnDestroy ######################### + + /** + * Called when component is destroyed + */ + public ngOnDestroy(): void + { + this.initSubscriptions.unsubscribe(); + this.input.element.removeEventListener('keydown', this.handleKeyboard); + this.input.element.removeEventListener('keypress', this.handleKeypress); + this.input.element.removeEventListener('select', this.handleSelect); + this.input.element.removeEventListener('click', this.handleClick); + } + + //######################### protected methods ######################### + + /** + * Handles selection of text inside of input + */ + @BindThis + protected handleSelect(): void + { + this.runWithValue(() => + { + //handles when all text is selected + if(this.inputElement.selectionStart == 0 && this.inputElement.selectionEnd == this.inputElement.value.length) + { + const result = this.parser.parse(this.inputElement.value, this.inputElement.selectionStart); + + this.inputElement.selectionStart = result.positionFrom; + this.inputElement.selectionEnd = result.positionTo; + } + }, + () => + { + //TODO: add support for ranges + }); + } + + /** + * Handles click event inside of input + */ + @BindThis + protected handleClick(): void + { + this.runWithValue(() => + { + const result = this.parser.parse(this.inputElement.value, this.inputElement.selectionStart ?? 0); + + this.inputElement.selectionStart = result.positionFrom; + this.inputElement.selectionEnd = result.positionTo; + }, + () => + { + //TODO: add support for ranges + }); + } + + /** + * Handles keyboard events + * @param event - Keyboard event that occured + */ + @BindThis + protected handleKeypress(event: KeyboardEvent): void + { + const selectionStart = this.inputElement.selectionStart ?? 0; + const selectionEnd = this.inputElement.selectionEnd ?? 0; + const newRawValueArray = this.inputElement.value.split(''); + newRawValueArray.splice(selectionStart , selectionEnd - selectionStart); + newRawValueArray.splice(selectionStart, 0, ...event.key); + const newRawValue = newRawValueArray.join(''); + + const [parsedValue] = parseRawInput(newRawValue, this.dateApi, this.dateTimeData, this.valueProvider); + + this.runWithValue(parsedValue => + { + if(this.minMaxConstraintTest(parsedValue)) + { + event.preventDefault(); + event.stopPropagation(); + } + }, + () => + { + //TODO: add support for ranges + }, + parsedValue); + } + + /** + * Handles keyboard events + * @param event - Keyboard event that occured + */ + @BindThis + protected handleKeyboard(event: KeyboardEvent): void + { + this.runWithValue(parsedValue => + { + const selectionStart = this.inputElement.selectionStart ?? 0; + + switch(event.key) + { + case 'ArrowRight': + case 'ArrowLeft': + { + event.preventDefault(); + event.stopPropagation(); + + const result = event.key == 'ArrowLeft' ? this.parser.previous(this.inputElement.value, selectionStart) : this.parser.next(this.inputElement.value, selectionStart); + + if(result) + { + this.inputElement.selectionStart = result.positionFrom; + this.inputElement.selectionEnd = result.positionTo; + } + + break; + } + case 'ArrowUp': + case 'ArrowDown': + { + event.preventDefault(); + event.stopPropagation(); + + let result = this.parser.parse(this.inputElement.value, selectionStart); + const selectionStartNew = result.positionFrom; + + this.stepChangeValue(parsedValue, result.part, event.key == 'ArrowUp'); + + result = this.parser.parse(this.inputElement.value, selectionStartNew); + + this.inputElement.selectionStart = result.positionFrom; + this.inputElement.selectionEnd = result.positionTo; + + break; + } + case 'Tab': + { + const result = event.shiftKey ? this.parser.previous(this.inputElement.value, selectionStart) : this.parser.next(this.inputElement.value, selectionStart); + + if(result) + { + event.preventDefault(); + event.stopPropagation(); + + this.inputElement.selectionStart = result.positionFrom; + this.inputElement.selectionEnd = result.positionTo; + } + + break; + } + case 'a': + { + if(event.ctrlKey) + { + event.preventDefault(); + event.stopPropagation(); + } + + break; + } + case 'Backspace': + { + this.input.value = null; + this.input.valueChange.next(); + + break; + } + case 'Escape': + { + this.picker?.hidePicker(); + + break; + } + case ' ': + { + if(event.ctrlKey) + { + this.picker?.showPicker(); + } + + break; + } + } + }, + () => + { + //TODO: add support for ranges + }); + } + + /** + * Tests whether are min or max constraint broken, returns true if constraint is broken + * @param value - Value to be tested + */ + protected minMaxConstraintTest(value: DateApiObject): boolean + { + return (!!this.dateTimeData.minDateTime && value.isBefore(this.dateTimeData.minDateTime)) || + (!!this.dateTimeData.maxDateTime && value.isAfter(this.dateTimeData.maxDateTime)); + } + + /** + * Runs code with check whether min max constrains was broken + * @param value - Value to be used checked for constrains + * @param code - Code that should be executed which can change current value + */ + protected withMinMaxConstraint(value: DateApiObject, code: () => void): void + { + value.updateOriginal(); + + code(); + + //min value constraint failure + if(this.minMaxConstraintTest(value)) + { + value.resetOriginal(); + } + + //value has changed, change input value + if(!value.isSame(value.originalValue)) + { + this.input.value = value.value; + this.input.valueChange.next(); + } + } + + /** + * Runs code for existing and valid value of date time + * @param singleValueCode - Code to be run when only single value can be inside of date time + * @param rangeValueCode - Code to be run when range value can be inside of date time + * @param parsedValueDefault - Default parsed value to be used + */ + protected runWithValue(singleValueCode: Action1>, rangeValueCode: Action1<[DateApiObject | null, DateApiObject | null]>, parsedValueDefault?: DateTimeObjectValue|undefined|null): void + { + const parsedValue = parsedValueDefault ?? parseDateTime(this.input.value, this.dateApi, null, this.dateTimeData.customFormat); + + if(!parsedValue) + { + return; + } + + if(Array.isArray(parsedValue)) + { + rangeValueCode(parsedValue); + } + else + { + //do nothing for invalid value + if(!parsedValue.isValid()) + { + return; + } + + singleValueCode(parsedValue); + } + } + + /** + * Changes current value of date for for specified part by single step + * @param value - Value to be used checked for constrains + * @param part - Part of date that should be changed + * @param increment - Indication whether value should be incremented or decremented + */ + protected stepChangeValue(value: DateApiObject, part: string, increment: boolean): void + { + switch(part) + { + case 'y': + case 'Y': + { + this.withMinMaxConstraint(value, () => increment ? value.addYears(1) : value.subtractYears(1)); + + break; + } + case 'Q': + { + break; + } + case 'M': + { + this.withMinMaxConstraint(value, () => increment ? value.addMonths(1) : value.subtractMonths(1)); + + break; + } + case 'w': + { + this.withMinMaxConstraint(value, () => increment ? value.addWeeks(1) : value.subtractWeeks(1)); + + break; + } + case 'd': + case 'D': + { + this.withMinMaxConstraint(value, () => increment ? value.addDays(1) : value.subtractDays(1)); + + break; + } + case 'H': + { + this.withMinMaxConstraint(value, () => increment ? value.addHours(1) : value.subtractHours(1)); + + break; + } + case 'm': + { + this.withMinMaxConstraint(value, () => increment ? value.addMinutes(1) : value.subtractMinutes(1)); + + break; + } + } + } +} diff --git a/src/directives/dateTimePickerInput/dateTimePickerInput.directive.ts b/src/directives/dateTimePickerInput/dateTimePickerInput.directive.ts new file mode 100644 index 0000000..081f0bb --- /dev/null +++ b/src/directives/dateTimePickerInput/dateTimePickerInput.directive.ts @@ -0,0 +1,25 @@ +import {Directive} from '@angular/core'; + +import {DatePickerInputSADirective} from '../datePickerInput/datePickerInput.directive'; +import {WithTimeSADirective} from '../withTime/withTime.directive'; + +/** + * Directive that combines date time picker with date time input + */ +@Directive( +{ + selector: 'input[dateTime][dateTimePickerInput]', + standalone: true, + hostDirectives: + [ + { + directive: DatePickerInputSADirective, + }, + { + directive: WithTimeSADirective, + }, + ], +}) +export class DateTimePickerInputSADirective +{ +} \ No newline at end of file diff --git a/src/directives/index.ts b/src/directives/index.ts index 45149ee..df76daa 100644 --- a/src/directives/index.ts +++ b/src/directives/index.ts @@ -1,5 +1,9 @@ +export * from './datePickerInput/datePickerInput.directive'; +export * from './dateTimeInputHandler/dateTimeInputHandler.directive'; +export * from './dateTimePickerInput/dateTimePickerInput.directive'; export * from './simpleDatePickerInput/simpleDatePickerInput.directive'; export * from './simpleDateTimeInputHandler/simpleDateTimeInputHandler.directive'; export * from './simpleDateTimePickerInput/simpleDateTimePickerInput.directive'; +export * from './withNow/withNow.directive'; export * from './withTime/withTime.directive'; export * from './withToday/withToday.directive'; diff --git a/src/directives/withNow/withNow.directive.ts b/src/directives/withNow/withNow.directive.ts new file mode 100644 index 0000000..173bd3f --- /dev/null +++ b/src/directives/withNow/withNow.directive.ts @@ -0,0 +1,47 @@ +import {Directive, Inject, OnDestroy} from '@angular/core'; +import {Subscription} from 'rxjs'; + +import {DATE_API} from '../../misc/tokens'; +import {DateTimeInputSADirective} from '../../modules'; +import {DateApi} from '../../services'; + +/** + * Directive that sets current date and time as day and time for empty date time on focus + */ +@Directive( +{ + selector: '[dateTime][withNow]', + standalone: true, +}) +export class WithNowSADirective implements OnDestroy +{ + //######################### protected fields ######################### + + /** + * Subscriptions created during initialization + */ + protected initSubscriptions: Subscription = new Subscription(); + + //######################### constructor ######################### + constructor(input: DateTimeInputSADirective, + @Inject(DATE_API) dateApi: DateApi,) + { + this.initSubscriptions.add(input.focus.subscribe(() => + { + if(!input.value) + { + input.value = dateApi.now().value; + } + })); + } + + //######################### public methods - implementation of OnDestroy ######################### + + /** + * Called when component is destroyed + */ + public ngOnDestroy(): void + { + this.initSubscriptions.unsubscribe(); + } +} \ No newline at end of file diff --git a/src/directives/withToday/withToday.directive.ts b/src/directives/withToday/withToday.directive.ts index 4ab470a..f00f3c7 100644 --- a/src/directives/withToday/withToday.directive.ts +++ b/src/directives/withToday/withToday.directive.ts @@ -6,7 +6,7 @@ import {DateTimeInputSADirective} from '../../modules'; import {DateApi} from '../../services'; /** - * Directive that sets today as day for empty date time on focus + * Directive that sets today (start of a day) as day for empty date time on focus */ @Directive( { @@ -15,22 +15,22 @@ import {DateApi} from '../../services'; }) export class WithTodaySADirective implements OnDestroy { - //######################### private fields ######################### + //######################### protected fields ######################### /** * Subscriptions created during initialization */ - private _initSubscriptions: Subscription = new Subscription(); + protected initSubscriptions: Subscription = new Subscription(); //######################### constructor ######################### constructor(input: DateTimeInputSADirective, @Inject(DATE_API) dateApi: DateApi,) { - this._initSubscriptions.add(input.focus.subscribe(() => + this.initSubscriptions.add(input.focus.subscribe(() => { if(!input.value) { - input.value = dateApi.now().value; + input.value = dateApi.now().startOfDay().value; } })); } @@ -42,6 +42,6 @@ export class WithTodaySADirective implements OnDestroy */ public ngOnDestroy(): void { - this._initSubscriptions.unsubscribe(); + this.initSubscriptions.unsubscribe(); } } \ No newline at end of file diff --git a/src/legacy/selector/components/inputDateTime/inputDateTime.component.css b/src/legacy/selector/components/inputDateTime/inputDateTime.component.css deleted file mode 100644 index d647491..0000000 --- a/src/legacy/selector/components/inputDateTime/inputDateTime.component.css +++ /dev/null @@ -1,9 +0,0 @@ -:host -{ - display: block; -} - -input -{ - width: 100%; -} \ No newline at end of file diff --git a/src/legacy/selector/components/inputDateTime/inputDateTime.component.html b/src/legacy/selector/components/inputDateTime/inputDateTime.component.html deleted file mode 100644 index 809bbb3..0000000 --- a/src/legacy/selector/components/inputDateTime/inputDateTime.component.html +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/src/legacy/selector/components/inputDateTime/inputDateTime.component.ts b/src/legacy/selector/components/inputDateTime/inputDateTime.component.ts deleted file mode 100644 index 8fa9ee3..0000000 --- a/src/legacy/selector/components/inputDateTime/inputDateTime.component.ts +++ /dev/null @@ -1,577 +0,0 @@ -// import {Component, ChangeDetectionStrategy, Inject, ChangeDetectorRef, ElementRef, ViewChild} from '@angular/core'; -// import {isPresent} from '@jscrpt/common'; -// import {Observable, Subject} from 'rxjs'; - -// import {DateTimeValue} from '../../../../interfaces/dateTime/datetime.interface'; -// import {DATE_API} from '../../../../misc/tokens'; -// import {DateApi, DateApiObject, DatePositionParser, DatePositionParserService, DateValueProvider} from '../../../../services'; -// import {DateTimeSelector} from '../../misc/datetimeSelector.interface'; - -// /** -// * Component used as datetime selector with input -// */ -// @Component( -// { -// selector: 'input-date-time-selector', -// templateUrl: 'inputDateTime.component.html', -// styleUrls: ['inputDateTime.component.css'], -// changeDetection: ChangeDetectionStrategy.OnPush -// }) -// export class InputDateTimeSelectorComponent implements DateTimeSelector -// { -// //######################### protected fields ######################### - -// /** -// * Occurs when value changes -// */ -// protected _valueChange: Subject = new Subject(); - -// /** -// * Occurs when selector is touched by user -// */ -// protected _touched: Subject = new Subject(); - -// /** -// * Occurs when selector requires picker to be displayed or hidden -// */ -// protected _pickerRequest: Subject = new Subject(); - -// /** -// * Instance of parser created for specific format -// */ -// protected _parser: DatePositionParser|null = null; - -// /** -// * Currently used format for displaying data -// */ -// protected _format: string = ''; - -// /** -// * Current value representation as date api wrapper -// */ -// protected _dateApiValue: null|DateApiObject = null; - -// /** -// * Indication whether is current value valid value -// */ -// protected _isValid: boolean = true; - -// /** -// * Minimal possible value that can be picked -// */ -// protected _minValue: TDate|null = null; - -// /** -// * Maximal possible value that can be picked -// */ -// protected _maxValue: TDate|null = null; - -// //######################### public properties - implementation of DateTimeSelector ######################### - -// /** -// * Gets or sets currently used format for displaying data -// */ -// public get format(): string -// { -// return this._format; -// } -// public set format(value: string) -// { -// if(isPresent(value)) -// { -// value = this._dateApi.getFormat(value); -// } - -// //only if format changes -// if(this._format != value) -// { -// this._parser = this._parserSvc.createParser(this._dateApi.getFormat(value)); -// } - -// this._format = value; -// } - -// /** -// * Gets or sets placeholder that is displayed when there is no value selected -// */ -// public placeholder: string|null = null; - -// /** -// * Gets current value of datetime -// */ -// public get value(): DateTimeValue|null -// { -// if(!this._dateApiValue || !this._isValid) -// { -// return null; -// } - -// return this._valueProvider.getValue(this._dateApiValue.value, this._format); -// } - -// /** -// * Gets formatted value -// */ -// public get formattedValue(): string|null -// { -// if(!this._isValid) -// { -// return null; -// } - -// return this.currentValue; -// } - -// /** -// * Gets indication whether is current value valid -// */ -// public get valid(): boolean -// { -// return this._isValid; -// } - -// /** -// * Occurs when value changes -// */ -// public get valueChange(): Observable -// { -// return this._valueChange.asObservable(); -// } - -// /** -// * Occurs when selector is touched by user -// */ -// public get touched(): Observable -// { -// return this._touched.asObservable(); -// } - -// /** -// * Occurs when selector requires picker to be displayed -// */ -// public get pickerRequest(): Observable -// { -// return this._pickerRequest.asObservable(); -// } - -// //######################### public properties - template bindings ######################### - -// /** -// * Indication whether is input disabled -// * @internal -// */ -// public disabled: boolean = false; - -// //######################### public properties - children ######################### - -// /** -// * Instance of html input element -// * @internal -// */ -// @ViewChild('input', {static: true}) -// public inputElement!: ElementRef; - -// //######################### protected properties ######################### - -// /** -// * Gets or sets string representation current of value -// */ -// protected get currentValue(): string|null -// { -// return this.input.value || null; -// } -// protected set currentValue(value: string|null) -// { -// if(this.input) -// { -// this.input.value = value ?? ''; -// } -// } - -// /** -// * Gets input element used for handling date time value -// */ -// protected get input(): HTMLInputElement -// { -// return this.inputElement.nativeElement; -// } - -// //######################### constructor ######################### -// constructor(@Inject(DATE_API) protected _dateApi: DateApi, -// protected _parserSvc: DatePositionParserService, -// protected _valueProvider: DateValueProvider, -// protected _changeDetector: ChangeDetectorRef) -// { -// } - -// //######################### public methods - implementation of DateTimeSelector ######################### - -// /** -// * Sets minimal possible value for picker, that can be picked -// * @param value - Minimal possible value that can be picked -// */ -// public setMinValue(value: TDate|null): void -// { -// this._minValue = value; -// } - -// /** -// * Sets maximal possible value for picker, that can be picked -// * @param value - Maximal possible value that can be picked -// */ -// public setMaxValue(value: TDate|null): void -// { -// this._maxValue = value; -// } - -// /** -// * Sets value of datetime selector -// * @param value - Value to be set to this selector -// */ -// public setValue(value: DateTimeValue|null): void -// { -// if(value?.from) -// { -// this._dateApiValue = this._dateApi.getValue(value?.from, this._format); -// this._isValid = this._dateApiValue.isValid(); - -// this._show(); -// } -// else -// { -// this._clearValue(); -// } -// } - -// /** -// * Sets as 'control' disabled -// * @param disabled - Indication whether sets value as disabled, if omitted it is same as disabled set to true -// */ -// public setDisabled(disabled: boolean = true): void -// { -// this.disabled = disabled; -// } - -// /** -// * Explicitly runs invalidation of content (change detection) -// */ -// public invalidateVisuals(): void -// { -// this._changeDetector.detectChanges(); -// } - -// //######################### public methods - template bindings ######################### - -// /** -// * Handles gaining of focus -// * @internal -// */ -// public handleFocus(): void -// { -// this._pickerRequest.next(true); - -// //no value -// if(!this._dateApiValue) -// { -// this._dateApiValue = this._dateApi.now(); -// this._isValid = this._dateApiValue.isValid(); - -// if(this._minMaxConstraintTest()) -// { -// this._clearValue(); -// } -// else -// { -// this._valueChange.next(); -// } -// } - -// if(!this._isValid) -// { -// return; -// } - -// this._show(); - -// const result = this._parser!.parse(this.currentValue!, this.input.selectionStart!); - -// this.input.selectionStart = result.positionFrom; -// this.input.selectionEnd = result.positionTo; -// } - -// /** -// * Handles blur on input -// * @internal -// */ -// public handleBlur(): void -// { -// this._pickerRequest.next(false); -// } - -// /** -// * Handles user input -// * @internal -// */ -// public handleInput(): void -// { -// //empty value -// if(!this.currentValue) -// { -// this._clearValue(); -// this._valueChange.next(); - -// return; -// } - -// this._dateApiValue = this._dateApi.getValue(this.currentValue, this._format); -// this._isValid = this._dateApiValue.isValid(); -// this._valueChange.next(); -// } - -// /** -// * Handles selection of text inside of input -// * @internal -// */ -// public handleSelect(): void -// { -// //handles when all text is selected -// if(this.currentValue && this.input.selectionStart == 0 && this.input.selectionEnd == this.input.value.length) -// { -// const result = this._parser!.parse(this.input.value, this.input.selectionStart!); - -// this.input.selectionStart = result.positionFrom; -// this.input.selectionEnd = result.positionTo; -// } -// } - -// /** -// * Handles click event inside of input -// * @internal -// */ -// public handleClick(): void -// { -// this._pickerRequest.next(true); - -// if(!this._dateApiValue) -// { -// return; -// } - -// const result = this._parser!.parse(this.input.value, this.input.selectionStart!); - -// this.input.selectionStart = result.positionFrom; -// this.input.selectionEnd = result.positionTo; -// } - -// /** -// * Handles keyboard events -// * @param event - Keyboard event that occured -// * @param input - Html input element that holds current value and selection -// * @internal -// */ -// public handleKeyboard(event: KeyboardEvent): void -// { -// if(!this._dateApiValue?.isValid()) -// { -// return; -// } - -// switch(event.key) -// { -// case 'ArrowRight': -// case 'ArrowLeft': -// { -// event.preventDefault(); -// event.stopPropagation(); - -// const result = event.key == 'ArrowLeft' ? this._parser!.previous(this.input.value, this.input.selectionStart!) : this._parser!.next(this.input.value, this.input.selectionStart!); - -// if(result) -// { -// this.input.selectionStart = result.positionFrom; -// this.input.selectionEnd = result.positionTo; -// } - -// break; -// } -// case 'ArrowUp': -// case 'ArrowDown': -// { -// event.preventDefault(); -// event.stopPropagation(); - -// let result = this._parser!.parse(this.input.value, this.input.selectionStart!); -// const selectionStart = result.positionFrom; - -// this._stepChangeValue(result.part, event.key == 'ArrowUp'); -// this._show(); - -// result = this._parser!.parse(this.input.value, selectionStart); - -// this.input.selectionStart = result.positionFrom; -// this.input.selectionEnd = result.positionTo; - -// break; -// } -// case 'Tab': -// { -// const result = event.shiftKey ? this._parser!.previous(this.input.value, this.input.selectionStart!) : this._parser!.next(this.input.value, this.input.selectionStart!); - -// if(result) -// { -// event.preventDefault(); -// event.stopPropagation(); - -// this.input.selectionStart = result.positionFrom; -// this.input.selectionEnd = result.positionTo; -// } - -// break; -// } -// case 'a': -// { -// if(event.ctrlKey) -// { -// event.preventDefault(); -// event.stopPropagation(); -// } - -// break; -// } -// case 'Backspace': -// { -// this._clearValue(); -// this._valueChange.next(); - -// break; -// } -// case 'Escape': -// { -// this._pickerRequest.next(false); - -// break; -// } -// case ' ': -// { -// if(event.ctrlKey) -// { -// this._pickerRequest.next(true); -// } - -// break; -// } -// } -// } - -// //######################### protected methods ######################### - -// /** -// * Shows current value in input -// */ -// protected _show(): void -// { -// if(this._isValid) -// { -// this.currentValue = this._dateApiValue?.format(this._format) ?? null; -// } -// } - -// /** -// * Tests whether are min or max constraint broken, returns true if constraint is broken -// */ -// protected _minMaxConstraintTest(): boolean -// { -// return (!!this._minValue && this._dateApiValue!.isBefore(this._minValue)) || -// (!!this._maxValue && this._dateApiValue!.isAfter(this._maxValue)); -// } - -// /** -// * Runs code with check whether min max constrains was broken -// * @param code - Code that should be executed which can change current value -// */ -// protected _withMinMaxConstraint(code: () => void): void -// { -// this._dateApiValue!.updateOriginal(); - -// code(); - -// //min value constraint failure -// if(this._minMaxConstraintTest()) -// { -// this._dateApiValue?.resetOriginal(); - -// return; -// } - -// this._valueChange.next(); -// } - -// /** -// * Clears current value -// */ -// protected _clearValue(): void -// { -// this._dateApiValue = null; -// this._isValid = true; -// this.currentValue = null; -// } - -// /** -// * Changes current value of date for for specified part by single step -// * @param part - Part of date that should be changed -// * @param increment - Indication whether value should be incremented or decremented -// */ -// protected _stepChangeValue(part: string, increment: boolean): void -// { -// if(!this._dateApiValue?.isValid()) -// { -// return; -// } - -// switch(part) -// { -// case 'y': -// case 'Y': -// { -// this._withMinMaxConstraint(() => increment ? this._dateApiValue!.addYears(1) : this._dateApiValue!.subtractYears(1)); - -// break; -// } -// case 'Q': -// { -// break; -// } -// case 'M': -// { -// this._withMinMaxConstraint(() => increment ? this._dateApiValue!.addMonths(1) : this._dateApiValue!.subtractMonths(1)); - -// break; -// } -// case 'w': -// { -// this._withMinMaxConstraint(() => increment ? this._dateApiValue!.addWeeks(1) : this._dateApiValue!.subtractWeeks(1)); - -// break; -// } -// case 'd': -// case 'D': -// { -// this._withMinMaxConstraint(() => increment ? this._dateApiValue!.addDays(1) : this._dateApiValue!.subtractDays(1)); - -// break; -// } -// case 'H': -// { -// this._withMinMaxConstraint(() => increment ? this._dateApiValue!.addHours(1) : this._dateApiValue!.subtractHours(1)); - -// break; -// } -// case 'm': -// { -// this._withMinMaxConstraint(() => increment ? this._dateApiValue!.addMinutes(1) : this._dateApiValue!.subtractMinutes(1)); - -// break; -// } -// } -// } -// } \ No newline at end of file diff --git a/src/legacy/selector/components/simpleInputDateTime/simpleInputDateTime.component.css b/src/legacy/selector/components/simpleInputDateTime/simpleInputDateTime.component.css deleted file mode 100644 index d647491..0000000 --- a/src/legacy/selector/components/simpleInputDateTime/simpleInputDateTime.component.css +++ /dev/null @@ -1,9 +0,0 @@ -:host -{ - display: block; -} - -input -{ - width: 100%; -} \ No newline at end of file diff --git a/src/legacy/selector/components/simpleInputDateTime/simpleInputDateTime.component.html b/src/legacy/selector/components/simpleInputDateTime/simpleInputDateTime.component.html deleted file mode 100644 index e66796b..0000000 --- a/src/legacy/selector/components/simpleInputDateTime/simpleInputDateTime.component.html +++ /dev/null @@ -1,9 +0,0 @@ - \ No newline at end of file diff --git a/src/legacy/selector/components/simpleInputDateTime/simpleInputDateTime.component.ts b/src/legacy/selector/components/simpleInputDateTime/simpleInputDateTime.component.ts deleted file mode 100644 index 6fa33ff..0000000 --- a/src/legacy/selector/components/simpleInputDateTime/simpleInputDateTime.component.ts +++ /dev/null @@ -1,430 +0,0 @@ -// import {Component, ChangeDetectionStrategy, Inject, ChangeDetectorRef, ElementRef, ViewChild} from '@angular/core'; -// import {isPresent} from '@jscrpt/common'; -// import {Observable, Subject} from 'rxjs'; - -// import {DateTimeValue} from '../../../../interfaces/dateTime/datetime.interface'; -// import {DATE_API} from '../../../../misc/tokens'; -// import {DateApi, DateApiObject, DateValueProvider} from '../../../../services'; -// import {DateTimeSelector} from '../../misc/datetimeSelector.interface'; - -// /** -// * Component used as datetime selector with simple input -// */ -// @Component( -// { -// selector: 'simple-input-date-time-selector', -// templateUrl: 'simpleInputDateTime.component.html', -// styleUrls: ['simpleInputDateTime.component.css'], -// changeDetection: ChangeDetectionStrategy.OnPush -// }) -// export class SimpleInputDateTimeSelectorComponent implements DateTimeSelector -// { -// //######################### protected fields ######################### - -// /** -// * Occurs when value changes -// */ -// protected _valueChange: Subject = new Subject(); - -// /** -// * Occurs when selector is touched by user -// */ -// protected _touched: Subject = new Subject(); - -// /** -// * Occurs when selector requires picker to be displayed or hidden -// */ -// protected _pickerRequest: Subject = new Subject(); - -// /** -// * Currently used format for displaying data -// */ -// protected _format: string = ''; - -// /** -// * Current value representation as date api wrapper -// */ -// protected _dateApiValue: null|DateApiObject = null; - -// /** -// * Indication whether is current value valid value -// */ -// protected _isValid: boolean = true; - -// /** -// * Minimal possible value that can be picked -// */ -// protected _minValue: TDate|null = null; - -// /** -// * Maximal possible value that can be picked -// */ -// protected _maxValue: TDate|null = null; - -// //######################### public properties - implementation of DateTimeSelector ######################### - -// /** -// * Gets or sets currently used format for displaying data -// */ -// public get format(): string -// { -// return this._format; -// } -// public set format(value: string) -// { -// if(isPresent(value)) -// { -// value = this._dateApi.getFormat(value); -// } - -// this._format = value; -// } - -// /** -// * Gets or sets placeholder that is displayed when there is no value selected -// */ -// public placeholder: string|null = null; - -// /** -// * Gets current value of datetime -// */ -// public get value(): DateTimeValue|null -// { -// if(!this._dateApiValue || !this._isValid) -// { -// return null; -// } - -// return this._valueProvider.getValue(this._dateApiValue.value, this._format); -// } - -// /** -// * Gets formatted value -// */ -// public get formattedValue(): string|null -// { -// if(!this._isValid) -// { -// return null; -// } - -// return this.currentValue; -// } - -// /** -// * Gets indication whether is current value valid -// */ -// public get valid(): boolean -// { -// return this._isValid; -// } - -// /** -// * Occurs when value changes -// */ -// public get valueChange(): Observable -// { -// return this._valueChange.asObservable(); -// } - -// /** -// * Occurs when selector is touched by user -// */ -// public get touched(): Observable -// { -// return this._touched.asObservable(); -// } - -// /** -// * Occurs when selector requires picker to be displayed -// */ -// public get pickerRequest(): Observable -// { -// return this._pickerRequest.asObservable(); -// } - -// //######################### public properties - template bindings ######################### - -// /** -// * Indication whether is input disabled -// * @internal -// */ -// public disabled: boolean = false; - -// //######################### public properties - children ######################### - -// /** -// * Instance of html input element -// * @internal -// */ -// @ViewChild('input', {static: true}) -// public inputElement?: ElementRef; - -// //######################### protected properties ######################### - -// /** -// * Gets or sets string representation current of value -// */ -// protected get currentValue(): string|null -// { -// return this.input.value || null; -// } -// protected set currentValue(value: string|null) -// { -// if(this.input) -// { -// this.input.value = value ?? ''; -// } -// } - -// /** -// * Gets input element used for handling date time value -// */ -// protected get input(): HTMLInputElement -// { -// return this.inputElement!.nativeElement; -// } - -// //######################### constructor ######################### -// constructor(@Inject(DATE_API) protected _dateApi: DateApi, -// protected _valueProvider: DateValueProvider, -// protected _changeDetector: ChangeDetectorRef) -// { -// } - -// //######################### public methods - implementation of DateTimeSelector ######################### - -// /** -// * Sets minimal possible value for picker, that can be picked -// * @param value - Minimal possible value that can be picked -// */ -// public setMinValue(value: TDate|null): void -// { -// this._minValue = value; -// } - -// /** -// * Sets maximal possible value for picker, that can be picked -// * @param value - Maximal possible value that can be picked -// */ -// public setMaxValue(value: TDate|null): void -// { -// this._maxValue = value; -// } - -// /** -// * Sets value of datetime selector -// * @param value - Value to be set to this selector -// */ -// public setValue(value: DateTimeValue|null): void -// { -// if(value?.from) -// { -// this._dateApiValue = this._dateApi.getValue(value?.from, this._format); -// this._isValid = this._dateApiValue.isValid(); - -// this._show(); -// } -// else -// { -// this._clearValue(); -// } -// } - -// /** -// * Sets as 'control' disabled -// * @param disabled - Indication whether sets value as disabled, if omitted it is same as disabled set to true -// */ -// public setDisabled(disabled: boolean = true): void -// { -// this.disabled = disabled; -// } - -// /** -// * Explicitly runs invalidation of content (change detection) -// */ -// public invalidateVisuals(): void -// { -// this._changeDetector.detectChanges(); -// } - -// //######################### public methods - template bindings ######################### - -// /** -// * Handles gaining of focus -// * @internal -// */ -// public handleFocus(): void -// { -// this._pickerRequest.next(true); - -// //no value -// if(!this._dateApiValue) -// { -// this._dateApiValue = this._dateApi.now(); -// this._isValid = this._dateApiValue.isValid(); - -// if(this._minMaxConstraintTest()) -// { -// this._clearValue(); -// } -// else -// { -// this._valueChange.next(); -// } -// } - -// if(!this._isValid) -// { -// return; -// } - -// this._show(); -// } - -// /** -// * Handles blur on input -// * @internal -// */ -// public handleBlur(): void -// { -// this._pickerRequest.next(false); -// } - -// /** -// * Handles user input -// * @internal -// */ -// public handleInput(): void -// { -// //empty value -// if(!this.currentValue) -// { -// this._clearValue(); -// this._valueChange.next(); - -// return; -// } - -// this._dateApiValue = this._dateApi.getValue(this.currentValue, this._format); -// this._isValid = this._dateApiValue.isValid(); -// this._valueChange.next(); -// } - -// /** -// * Handles click event inside of input -// * @internal -// */ -// public handleClick(): void -// { -// this._pickerRequest.next(true); -// } - -// /** -// * Handles keyboard events -// * @param event - Keyboard event that occured -// * @param input - Html input element that holds current value and selection -// * @internal -// */ -// public handleKeyboard(event: KeyboardEvent): void -// { -// if(!this._dateApiValue?.isValid()) -// { -// return; -// } - -// switch(event.key) -// { -// case 'ArrowRight': -// case 'ArrowLeft': -// { -// event.preventDefault(); -// event.stopPropagation(); - -// this._withMinMaxConstraint(() => event.key == 'ArrowLeft' ? this._dateApiValue!.subtractDays(1) : this._dateApiValue!.addDays(1)); -// this._show(); - -// break; -// } -// case 'ArrowUp': -// case 'ArrowDown': -// { -// event.preventDefault(); -// event.stopPropagation(); - -// this._withMinMaxConstraint(() => event.key == 'ArrowUp' ? this._dateApiValue!.subtractWeeks(1) : this._dateApiValue!.addWeeks(1)); -// this._show(); - -// break; -// } -// case 'Escape': -// { -// this._pickerRequest.next(false); - -// break; -// } -// case ' ': -// { -// if(event.ctrlKey) -// { -// this._pickerRequest.next(true); -// } - -// break; -// } -// } -// } - -// //######################### protected methods ######################### - -// /** -// * Clears current value -// */ -// protected _clearValue(): void -// { -// this._dateApiValue = null; -// this._isValid = true; -// this.currentValue = null; -// } - -// /** -// * Tests whether are min or max constraint broken, returns true if constraint is broken -// */ -// protected _minMaxConstraintTest(): boolean -// { -// return (!!this._minValue && this._dateApiValue!.isBefore(this._minValue)) || -// (!!this._maxValue && this._dateApiValue!.isAfter(this._maxValue)); -// } - -// /** -// * Runs code with check whether min max constrains was broken -// * @param code - Code that should be executed which can change current value -// */ -// protected _withMinMaxConstraint(code: () => void): void -// { -// this._dateApiValue!.updateOriginal(); - -// code(); - -// //min value constraint failure -// if(this._minMaxConstraintTest()) -// { -// this._dateApiValue?.resetOriginal(); - -// return; -// } - -// this._valueChange.next(); -// } - -// /** -// * Shows current value in input -// */ -// protected _show(): void -// { -// if(this._isValid) -// { -// this.currentValue = this._dateApiValue?.format(this._format) ?? null; -// } -// } -// } \ No newline at end of file diff --git a/src/misc/utils.ts b/src/misc/utils.ts index 6c7e2ee..920e60a 100644 --- a/src/misc/utils.ts +++ b/src/misc/utils.ts @@ -1,7 +1,8 @@ import {isBlank, isJsObject, isPresent, isString, nameof} from '@jscrpt/common'; import {DateTimeValue} from '../interfaces'; -import {DateApi, DateApiObject, DateValue} from '../services'; +import type {DateTimeSADirective} from '../modules/dateTime/directives/dateTime/dateTime.directive'; +import {DateApi, DateApiObject, DateValue, DateValueProvider} from '../services'; import {DateTimeValueFormat} from './enums'; import {DateTimeInputOutputValue, DateTimeObjectValue} from './types'; @@ -156,4 +157,86 @@ export function getSingleDateTimeValue(value: DateTimeInputOutputValue(rawValue: string, + dateApi: DateApi, + dateTimeData: DateTimeSADirective, + valueProvider: DateValueProvider,): [DateTimeObjectValue|undefined|null, DateTimeInputOutputValue|undefined|null] +{ + if(!rawValue) + { + return [null, null]; + } + + const internalValue = getInternalValue(rawValue, dateApi, dateTimeData, valueProvider); + const value = formatDateTime(internalValue, dateTimeData.valueFormat, dateTimeData.customFormat); + + return [internalValue, value]; +} + +/** + * Gets internal value and fix lowest time difference + * @param value - Value to be get as internal value + * @param dateApi - Date api for manipulation with date + * @param dateTimeData - Object storing information about format + * @param valueProvider - Provider used for obtaining rounded value according format + */ +export function getInternalValue(value: DateTimeInputOutputValue|undefined|null, + dateApi: DateApi, + dateTimeData: DateTimeSADirective, + valueProvider: DateValueProvider,): DateTimeObjectValue|undefined|null +{ + let internalValue = parseDateTime(value, dateApi, null, dateTimeData.customFormat); + + if(isBlank(internalValue)) + { + return; + } + + //update for specified format, round value + + //ranged value + if(Array.isArray(internalValue)) + { + const [from, to] = internalValue; + + if(from) + { + const val = valueProvider.getValue(from.value, dateTimeData.customFormat).from; + + if(val) + { + internalValue[0] = dateApi.getValue(val, dateTimeData.customFormat); + } + } + + if(to) + { + const val = valueProvider.getValue(to.value, dateTimeData.customFormat).to; + + if(val) + { + internalValue[1] = dateApi.getValue(val, dateTimeData.customFormat); + } + } + } + else + { + const val = valueProvider.getValue(internalValue.value, dateTimeData.customFormat).from; + + if(val) + { + internalValue = dateApi.getValue(val, dateTimeData.customFormat); + } + } + + return internalValue; } \ No newline at end of file diff --git a/src/modules/dateTime/directives/dateTime/dateTime.directive.ts b/src/modules/dateTime/directives/dateTime/dateTime.directive.ts index 508eea2..869004a 100644 --- a/src/modules/dateTime/directives/dateTime/dateTime.directive.ts +++ b/src/modules/dateTime/directives/dateTime/dateTime.directive.ts @@ -32,6 +32,11 @@ export class DateTimeSADirective implements OnDestroy */ protected minDateTimeChangesSubject: Subject = new Subject(); + /** + * Subject used for emitting changes in custom format value + */ + protected customFormatChangesSubject: Subject = new Subject(); + /** * Subscription for max date instance value changes */ @@ -45,22 +50,22 @@ export class DateTimeSADirective implements OnDestroy /** * Max allowed value of date time */ - protected ɵMaxDateTime: TDate|undefined|null; + protected ɵmaxDateTime: TDate|undefined|null; /** * Min allowed value of date time */ - protected ɵMinDateTime: TDate|undefined|null; + protected ɵminDateTime: TDate|undefined|null; /** * Date time value format which is being worked with in this date time */ - protected ɵValueFormat: DateTimeValueFormat = DateTimeValueFormat.DateInstance; + protected ɵvalueFormat: DateTimeValueFormat = DateTimeValueFormat.DateInstance; /** * Format of string representation of date */ - protected ɵFormat: keyof FormatProvider = 'date'; + protected ɵformat: keyof FormatProvider = 'date'; /** * Date api instance, used for date time manipulation @@ -72,6 +77,11 @@ export class DateTimeSADirective implements OnDestroy */ protected formatProvider: FormatProvider = inject(FORMAT_PROVIDER); + /** + * Custom format string representation of date + */ + protected ɵcustomFormat: string = this.dateApi.getFormat(this.formatProvider[this.ɵformat]); + //######################### public properties ######################### /** @@ -90,6 +100,14 @@ export class DateTimeSADirective implements OnDestroy return this.minDateTimeChangesSubject.asObservable(); } + /** + * Occurs when there are changes in custom format value + */ + public get customFormatChanges(): Observable + { + return this.customFormatChangesSubject.asObservable(); + } + //######################### public properties - inputs ######################### /** @@ -98,18 +116,18 @@ export class DateTimeSADirective implements OnDestroy @Input() public get valueFormat(): DateTimeValueFormat { - return this.ɵValueFormat; + return this.ɵvalueFormat; } public set valueFormat(value: DateTimeValueFormat) { if(isString(value)) { - this.ɵValueFormat = DateTimeValueFormat[value] as unknown as DateTimeValueFormat; + this.ɵvalueFormat = DateTimeValueFormat[value] as unknown as DateTimeValueFormat; return; } - this.ɵValueFormat = value; + this.ɵvalueFormat = value; } /** @@ -118,19 +136,27 @@ export class DateTimeSADirective implements OnDestroy @Input() public get format(): keyof FormatProvider { - return this.ɵFormat; + return this.ɵformat; } public set format(value: keyof FormatProvider) { - this.ɵFormat = value; + this.ɵformat = value; this.customFormat = this.dateApi.getFormat(this.formatProvider[value]); } /** - * Custom format string representation of date + * Gets or sets custom format string representation of date */ @Input() - public customFormat: string = this.dateApi.getFormat(this.formatProvider[this.ɵFormat]); + public get customFormat(): string + { + return this.ɵcustomFormat; + } + public set customFormat(value: string) + { + this.ɵcustomFormat = value; + this.customFormatChangesSubject.next(); + } /** * Gets or sets max allowed date for date time @@ -138,7 +164,7 @@ export class DateTimeSADirective implements OnDestroy @Input() public get maxDateTime(): TDate|undefined|null { - return this.ɵMaxDateTime; + return this.ɵmaxDateTime; } public set maxDateTime(value: TDate|undefined|null) { @@ -191,7 +217,7 @@ export class DateTimeSADirective implements OnDestroy @Input() public get minDateTime(): TDate|undefined|null { - return this.ɵMinDateTime; + return this.ɵminDateTime; } public set minDateTime(value: TDate|undefined|null) { @@ -261,7 +287,7 @@ export class DateTimeSADirective implements OnDestroy @BindThis protected minDateSet(value: TDate|undefined|null): void { - this.ɵMinDateTime = value; + this.ɵminDateTime = value; this.minDateTimeChangesSubject.next(); this.onMinDateTimeChange(); } @@ -273,7 +299,7 @@ export class DateTimeSADirective implements OnDestroy @BindThis protected maxDateSet(value: TDate|undefined|null): void { - this.ɵMaxDateTime = value; + this.ɵmaxDateTime = value; this.maxDateTimeChangesSubject.next(); this.onMaxDateTimeChange(); }