UNPKG

@progress/kendo-angular-dateinputs

Version:

Kendo UI for Angular Date Inputs Package - Everything you need to add date selection functionality to apps (DatePicker, TimePicker, DateInput, DateRangePicker, DateTimePicker, Calendar, and MultiViewCalendar).

1,262 lines (1,257 loc) 46 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Component, ChangeDetectionStrategy, ChangeDetectorRef, Input, Output, ViewChild, EventEmitter, ElementRef, HostBinding, isDevMode, Renderer2, forwardRef, NgZone, Optional, Injector } from '@angular/core'; import { minValidator } from '../validators/min.validator'; import { maxValidator } from '../validators/max.validator'; import { incompleteDateValidator } from '../validators/incomplete-date.validator'; import { NG_VALUE_ACCESSOR, NG_VALIDATORS, NgControl } from '@angular/forms'; import { L10N_PREFIX, LocalizationService } from '@progress/kendo-angular-l10n'; import { IntlService, localeData } from '@progress/kendo-angular-intl'; import { validatePackage } from '@progress/kendo-licensing'; import { packageMetadata } from '../package-metadata'; import { cloneDate, isEqual } from '@progress/kendo-date-math'; import { hasObservers, isControlRequired, KendoInput, setHTMLAttributes, removeHTMLAttributes, isObjectPresent, parseAttributes, anyChanged, EventsOutsideAngularDirective } from '@progress/kendo-angular-common'; import { Arrow } from './arrow.enum'; import { noop, isValidRange, getSizeClass, getRoundedClass, getFillModeClass, DEFAULT_FILL_MODE, DEFAULT_ROUNDED, DEFAULT_SIZE } from '../util'; import { PickerService } from '../common/picker.service'; import { closest } from '../common/dom-queries'; import { requiresZoneOnBlur, isPresent, attributeNames } from '../common/utils'; import { Subscription } from 'rxjs'; import { caretAltDownIcon, caretAltUpIcon, xIcon } from '@progress/kendo-svg-icons'; import { DateInput } from '@progress/kendo-dateinputs-common'; import { IconWrapperComponent } from '@progress/kendo-angular-icons'; import { NgIf } from '@angular/common'; import { DateInputLocalizedMessagesDirective } from './localization/dateinput-localized-messages.directive'; import { MAX_DATE, MIN_DATE } from '../defaults'; import * as i0 from "@angular/core"; import * as i1 from "@progress/kendo-angular-intl"; import * as i2 from "@progress/kendo-angular-l10n"; import * as i3 from "../common/picker.service"; let nextId = 0; const MIN_DOC_LINK = 'https://www.telerik.com/kendo-angular-ui/components/dateinputs/api/DateInputComponent/#toc-min'; const MAX_DOC_LINK = 'https://www.telerik.com/kendo-angular-ui/components/dateinputs/api/DateInputComponent/#toc-max'; const VALUE_DOC_LINK = 'https://www.telerik.com/kendo-angular-ui/components/dateinputs/dateinput/#toc-using-with-json'; const TWO_DIGIT_YEAR_MAX = 68; const DEFAULT_FORMAT = 'd'; const DEFAULT_FORMAT_PLACEHOLDER = 'wide'; const DATE_PART_REGEXP = /year|month|<day>/; const TIME_PART_REGEXP = /hour|minute|second|millisecond/; /** * @hidden * Need to overrite `dateFormatNames` parameters order and provide `cldr` object * required by the kendo-dateinputs-common package */ export class DateInputIntl { service; format; toString; formatDate; parseDate; parseNumber; formatNumber; splitDateFormat; numberSymbols; firstDay; weekendRange; dateFieldName; dateFormatNames; cldr = {}; localeId; constructor(service) { this.service = service; this.localeId = service['localeId']; this.format = service.format; this.toString = service.toString; this.formatDate = service.formatDate; this.parseDate = service.parseDate; this.parseNumber = service.parseNumber; this.formatNumber = service.formatNumber; this.splitDateFormat = service.splitDateFormat; this.numberSymbols = service.numberSymbols; this.firstDay = service.firstDay; this.weekendRange = service.weekendRange; this.dateFieldName = service.dateFieldName; this.dateFormatNames = (localeId, options) => this.service.dateFormatNames(options, localeId || this.localeId); const _localeData = localeData(this.localeId); // Setting the `cldr` object from here could be avoided if the logic in the common package is revisited to // directly relies on the `localeId` being set as part of the options => TBD and validated for all suites this.cldr[_localeData.name] = _localeData; } } /** * Represents the [Kendo UI DateInput component for Angular](slug:overview_dateinput). */ export class DateInputComponent { cdr; intl; renderer; wrapper; ngZone; injector; localization; pickerService; /** * @hidden */ caretAltUpIcon = caretAltUpIcon; /** * @hidden */ xIcon = xIcon; /** * @hidden */ caretAltDownIcon = caretAltDownIcon; /** * @hidden */ set focusableId(_focusableId) { if (_focusableId) { this._focusableId = _focusableId; } } get focusableId() { return this._focusableId; } /** * @hidden */ set pickerType(_pickerType) { if (_pickerType) { this.focusableId = `${_pickerType}-${nextId}`; } } /** * If set to `true`, renders a clear button after the input text or DateInput value has been changed. * Clicking this button resets the value of the component to `null` and triggers the `valueChange` event. * @default false */ clearButton = false; /** * Sets or gets the `disabled` property of the DateInput and * determines whether the component is active * ([see example]({% slug disabled_dateinput %})). * To learn how to disable the component in reactive forms, refer to the article on [Forms Support](slug:formssupport_dateinput#toc-managing-the-dateinput-disabled-state-in-reactive-forms). */ disabled = false; /** * Sets or gets the read-only state of the DateInput * ([see example]({% slug readonly_dateinput %})). * * @default false */ readonly = false; /** * Sets the title of the input element of the DateInput. */ title = ""; /** * Sets or gets the `tabIndex` property of the DateInput. */ tabindex = 0; /** * @hidden */ role = 'textbox'; /** * @hidden */ ariaReadOnly = false; /** * @hidden */ set tabIndex(tabIndex) { this.tabindex = tabIndex; } get tabIndex() { return this.tabindex; } /** * @hidden */ isRequired = false; /** * Specifies the date format that is used to display the input value * ([see example]({% slug formats_dateinput %})). * * Format value options: * - `string` - Provide a `string` if a single format is going to be used regardless whether the input is focused or blurred. * - [`FormatSettings`]({% slug api_dateinputs_formatsettings %}) - To display different formats when the component is focused or blurred, provide a settings object with specified `inputFormat` and `displayFormat` values. */ format = DEFAULT_FORMAT; /** * Defines the descriptions of the format sections in the input field. * For more information, refer to the article on * [placeholders]({% slug placeholders_dateinput %}). * * @example * ```ts * _@Component({ * selector: 'my-app', * template: ` * <div class="row example-wrapper" [style.min-height.px]="450"> * <div class="col-xs-12 col-md-6 example-col"> * <p>Full-length format description:</p> * <kendo-dateinput formatPlaceholder="wide"></kendo-dateinput> * </div> * * <div class="col-xs-12 col-md-6 example-col"> * <p>Narrow-length format description:</p> * <kendo-dateinput formatPlaceholder="narrow"></kendo-dateinput> * </div> * * <div class="col-xs-12 col-md-6 example-col"> * <p>Short-length format description:</p> * <kendo-dateinput formatPlaceholder="short"></kendo-dateinput> * </div> * * <div class="col-xs-12 col-md-6 example-col"> * <p>Display defined format:</p> * <kendo-dateinput format="MM/dd/yyyy" formatPlaceholder="formatPattern"></kendo-dateinput> * </div> * * <div class="col-xs-12 col-md-6 example-col"> * <p>Custom defined format descriptions</p> * <kendo-dateinput format="G" * [formatPlaceholder]="{ * year: 'y', month: 'M', day: 'd', * hour: 'h', minute: 'm', second: 's' * }" * ></kendo-dateinput> * </div> * </div> * ` * }) * export class AppComponent { } * ``` */ set formatPlaceholder(format) { this._formatPlaceholder = format ? format : DEFAULT_FORMAT_PLACEHOLDER; } get formatPlaceholder() { return this._formatPlaceholder; } /** * Specifies the hint the DateInput displays when its value is `null`. * For more information, refer to the article on * [placeholders]({% slug placeholders_dateinput %}). * * @example * ```ts * _@Component({ * selector: 'my-app', * template: ` * <kendo-dateinput placeholder="Enter birth date..."></kendo-dateinput> * ` * }) * export class AppComponent { } * ``` */ placeholder = null; /** * Configures the incremental steps of the DateInput. * For more information, refer to the article on * [incremental steps]({% slug incrementalsteps_dateinput %}). * * @example * ```ts * _@Component({ * selector: 'my-app', * template: ` * <kendo-dateinput [steps]="steps"></kendo-dateinput> * ` * }) * export class AppComponent { * public steps = { year: 10, month: 1, day: 5 }; * } * ``` */ steps = {}; /** * Specifies the biggest date that is valid * ([see example]({% slug dateranges_dateinput %})). * By default, the `max` value is `2099-12-31`. */ max = cloneDate(MAX_DATE); /** * Specifies the smallest date that is valid * ([see example]({% slug dateranges_dateinput %})). * By default, the `min` value is `1900-1-1`. */ min = cloneDate(MIN_DATE); /** * Determines whether the built-in min or max validators are to be enforced when a form is being validated. * * @default true */ rangeValidation = true; /** * Determines whether to autocorrect invalid segments automatically. * * @default true */ autoCorrectParts = true; /** * Determines whether to automatically move to the next segment after the user completes the current one. * * @default true */ autoSwitchParts = true; /** * A string array representing custom keys, which will move the focus to the next date format segment. */ autoSwitchKeys = []; /** * Determines if the users should see a blinking caret inside the Date Input when possible. * * @default false */ allowCaretMode = false; /** * When enabled, the DateInput will autofill the rest of the date to the current date when the component loses focus. * * @default false */ autoFill = false; /** * Determines whether the built-in validation for incomplete dates is to be enforced when a form is being validated. */ incompleteDateValidation = false; /** * The maximum year to assume to be from the current century when typing two-digit year value * ([see example]({% slug formats_dateinput %}#toc-two-digit-year-format)). * * The default value is 68, indicating that typing any value less than 69 * will be assumed to be 20xx, while 69 and larger will be assumed to be 19xx. */ twoDigitYearMax = TWO_DIGIT_YEAR_MAX; /** * Indicates whether the mouse scroll can be used to increase/decrease the time segments values. * * @default true */ enableMouseWheel = true; /** * Specifies the value of the DateInput component. * * > The `value` has to be a valid [JavaScript `Date`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date) instance or `null`. */ set value(value) { this.verifyValue(value); this.showClearButton = value || (!value && this.isDateIncomplete) ? true : false; this._value = cloneDate(value); this.valueUpdate.emit(cloneDate(value)); } get value() { return this._value; } /** * Specifies whether the **Up** and **Down** spin buttons will be rendered. * For more information, refer to the article on * [spinner buttons]({% slug spinbuttons_dateinput %}). */ spinners = false; /** * @hidden */ isPopupOpen; /** * @hidden */ hasPopup; /** * Sets the size of the component. * * The possible values are: * * `small` * * `medium` (Default) * * `large` * * `none` * */ set size(size) { this.renderer.removeClass(this.wrapper.nativeElement, getSizeClass('input', this.size)); const newSize = size ? size : DEFAULT_SIZE; if (newSize !== 'none') { this.renderer.addClass(this.wrapper.nativeElement, getSizeClass('input', newSize)); } this._size = newSize; } get size() { return this._size; } /** * Sets the border radius of the component. * * The possible values are: * * `small` * * `medium` (Default) * * `large` * * `full` * * `none` * */ set rounded(rounded) { this.renderer.removeClass(this.wrapper.nativeElement, getRoundedClass(this.rounded)); const newRounded = rounded ? rounded : DEFAULT_ROUNDED; if (newRounded !== 'none') { this.renderer.addClass(this.wrapper.nativeElement, getRoundedClass(newRounded)); } this._rounded = newRounded; } get rounded() { return this._rounded; } /** * Sets the fillMode of the component. * * The possible values are: * * `solid` (Default) * * `flat` * * `outline` * * `none` * */ set fillMode(fillMode) { this.renderer.removeClass(this.wrapper.nativeElement, getFillModeClass('input', this.fillMode)); const newFillMode = fillMode ? fillMode : DEFAULT_FILL_MODE; if (newFillMode !== 'none') { this.renderer.addClass(this.wrapper.nativeElement, getFillModeClass('input', newFillMode)); if (this.spinners && this.spinup && this.spindown) { this.setSpinnerFill(this.spinup.nativeElement, newFillMode, this.fillMode); this.setSpinnerFill(this.spindown.nativeElement, newFillMode, this.fillMode); } } this._fillMode = newFillMode; } get fillMode() { return this._fillMode; } /** * Sets the HTML attributes of the inner focusable input element. Attributes which are essential for certain component functionalities cannot be changed. */ set inputAttributes(attributes) { if (isObjectPresent(this.parsedAttributes)) { removeHTMLAttributes(this.parsedAttributes, this.renderer, this.dateInput.nativeElement); } this._inputAttributes = attributes; this.parsedAttributes = this.inputAttributes ? parseAttributes(this.inputAttributes, this.defaultAttributes) : this.inputAttributes; this.setInputAttributes(); } get inputAttributes() { return this._inputAttributes; } /** * Fires each time the user selects a new value * ([see example](slug:events_dateinput)). */ valueChange = new EventEmitter(); /** * @hidden * Fires each time the user selects a new value * ([see example](slug:events_dateinput)). */ valueUpdate = new EventEmitter(); /** * Fires each time the user focuses the input element * ([see example](slug:events_dateinput)). */ onFocus = new EventEmitter(); /** * Fires each time the input element gets blurred * ([see example](slug:events_dateinput)). */ onBlur = new EventEmitter(); /** * @hidden */ dateInput; get wrapperClass() { return true; } get disabledClass() { return this.disabled; } get inputElement() { return this.dateInput ? this.dateInput.nativeElement : null; } get inputValue() { return (this.inputElement || {}).value || ''; } get isActive() { return this._active; } set isActive(value) { this._active = value; if (!this.wrapper) { return; } if (!isPresent(this.pickerService)) { const element = this.wrapper.nativeElement; if (value) { this.renderer.addClass(element, 'k-focus'); } else { this.renderer.removeClass(element, 'k-focus'); } } } /** * @hidden */ get formControl() { const ngControl = this.injector.get(NgControl, null); return ngControl?.control || null; } get options() { return { format: this.format, steps: this.steps, readonly: this.readonly, formatPlaceholder: this.formatPlaceholder, placeholder: this.placeholder, autoCorrectParts: this.autoCorrectParts, autoSwitchParts: this.autoSwitchParts, selectPreviousSegmentOnBackspace: true, autoSwitchKeys: this.autoSwitchKeys, twoDigitYearMax: this.twoDigitYearMax, enableMouseWheel: this.enableMouseWheel, selectNearestSegmentOnFocus: true, allowCaretMode: this.allowCaretMode, autoFill: this.autoFill, value: this.value, intlService: new DateInputIntl(this.intl) }; } arrow = Arrow; arrowDirection = Arrow.None; formatSections = { date: false, time: false }; hasMousedown = false; focusedPriorToMousedown = false; showClearButton = false; /** * @hidden */ isDateIncomplete = false; currentFormat = ""; spinup; spindown; minValidator = noop; maxValidator = noop; incompleteValidator = noop; _value = null; _active = false; _focusableId = `dateinput-${nextId++}`; _formatPlaceholder = DEFAULT_FORMAT_PLACEHOLDER; kendoDate = null; kendoDateObject = null; domEvents = []; ngControl; onControlChange = noop; onControlTouched = noop; onValidatorChange = noop; _size = DEFAULT_SIZE; _rounded = DEFAULT_ROUNDED; _fillMode = DEFAULT_FILL_MODE; control; subs = new Subscription(); _inputAttributes; parsedAttributes = {}; get defaultAttributes() { return { 'aria-readonly': this.ariaReadOnly, id: this.focusableId, title: this.title, tabindex: this.tabindex, disabled: this.disabled ? '' : null, readonly: this.readonly ? '' : null, placeholder: this.placeholder, 'aria-expanded': this.isPopupOpen, 'aria-haspopup': this.hasPopup, required: this.isControlRequired ? '' : null }; } get mutableAttributes() { return { autocomplete: 'off', autocorrect: 'off', autocapitalize: 'off', spellcheck: 'false', role: this.role }; } constructor(cdr, intl, renderer, wrapper, ngZone, injector, localization, pickerService) { this.cdr = cdr; this.intl = intl; this.renderer = renderer; this.wrapper = wrapper; this.ngZone = ngZone; this.injector = injector; this.localization = localization; this.pickerService = pickerService; validatePackage(packageMetadata); if (this.pickerService) { this.pickerService.input = this; } else { this.ariaReadOnly = null; } } /** * @hidden * Used by the TextBoxContainer to determine if the component is empty */ isEmpty() { const currentValue = this.dateInput.nativeElement.value; return !currentValue || !String(currentValue).trim(); } /** * @hidden */ handleDragAndDrop(args) { args.preventDefault(); } /** * @hidden */ containsElement(element) { return Boolean(closest(element, node => node === this.wrapper.nativeElement)); } /** * @hidden */ ngOnInit() { if (this.kendoDate) { this.kendoDate.destroy(); } this.kendoDate = this.initKendoDate(); this.kendoDateObject = this.kendoDate.dateObject; this.updateFormatSections(); this.subs.add(this.intl.changes.subscribe(this.intlChange.bind(this))); this.ngControl = this.injector.get(NgControl, null); if (this.wrapper) { this.renderer.removeAttribute(this.wrapper.nativeElement, 'tabindex'); } this.minValidator = this.rangeValidation ? minValidator(this.min) : noop; this.maxValidator = this.rangeValidation ? maxValidator(this.max) : noop; } /** * @hidden */ ngOnChanges(changes) { this.verifyRange(); if (anyChanged(['min', 'max', 'rangeValidation', 'incompleteDateValidation'], changes, false)) { this.minValidator = this.rangeValidation ? minValidator(this.min) : noop; this.maxValidator = this.rangeValidation ? maxValidator(this.max) : noop; this.incompleteValidator = this.incompleteDateValidation ? incompleteDateValidator() : noop; this.onValidatorChange(); } if (changes['clearButton']) { this.showClearButton = this.clearButton && (isPresent(this.value) || this.isDateIncomplete); } const isEqualToKendoDate = this.kendoDate && isEqual(this.value, this.kendoDate.value); if (!isEqualToKendoDate) { if (!this.kendoDate) { return; } this.kendoDate.writeValue(this.value); } if (changes['format'] || changes['placeholder']) { if (!this.kendoDate) { return; } this.kendoDate?.setOptions(this.options, true); this.updateFormatSections(); } if (anyChanged(['enableMouseWheel', 'autoFill', 'autoSwitchParts', 'autoSwitchKeys', 'twoDigitYearMax', 'allowCaretMode', 'autoCorrectParts', 'readonly', 'steps', 'formatPlaceholder'], changes)) { if (!this.kendoDate) { return; } this.kendoDate?.setOptions(this.options, true); } } updateFormatSections() { this.formatSections = this.intl.splitDateFormat(this.kendoDate.inputFormat) .reduce(({ date, time }, p) => { return { date: date || DATE_PART_REGEXP.test(p.type), time: time || TIME_PART_REGEXP.test(p.type) }; }, { date: false, time: false }); } updateIncompleteValidationStatus() { const previousValue = this.isDateIncomplete; this.isDateIncomplete = this.kendoDateObject.hasValue() && this.value === null; if (previousValue === this.isDateIncomplete || !this.incompleteDateValidation) { return; } if (isPresent(this.ngControl) && !isPresent(this.pickerService)) { this.cdr.markForCheck(); this.ngZone.run(() => this.onValidatorChange()); } else if (isPresent(this.pickerService)) { this.pickerService.dateCompletenessChange.emit(); } } ngAfterViewInit() { this.setComponentClasses(); const formControl = this.injector.get(NgControl, null)?.control; this.control = formControl; this.subs.add(this.formControl?.statusChanges.subscribe(() => this.setAriaInvalid())); this.setAriaInvalid(); this.subs.add(this.dateInput?.nativeElement.addEventListener('keydown', this.handleKeyDown, true)); } ngOnDestroy() { this.subs.unsubscribe(); if (this.pickerService) { this.pickerService.input = null; } this.domEvents.forEach(unbindCallback => unbindCallback()); } /** * @hidden */ setAriaInvalid() { if (!this.control) { return; } if (this.control.invalid) { this.renderer.setAttribute(this.inputElement, attributeNames.ariaInvalid, 'true'); } else { this.renderer.setAttribute(this.inputElement, attributeNames.ariaInvalid, 'false'); } } /** * @hidden */ get isControlRequired() { return isControlRequired(this.formControl) || this.isRequired; } /** * @hidden */ validate(control) { return this.minValidator(control) || this.maxValidator(control) || this.incompleteValidator(control, this.isDateIncomplete); } /** * @hidden */ registerOnValidatorChange(fn) { this.onValidatorChange = fn; } /** * @hidden */ setDisabledState(isDisabled) { this.disabled = isDisabled; this.cdr.markForCheck(); } //ngModel binding /** * @hidden */ writeValue(value) { this.verifyValue(value); this.value = cloneDate(value); this.kendoDate?.setOptions(this.options, true); this.kendoDateObject?.setValue(this.value); this.kendoDate?.refreshElementValue(); } resetInput() { this.isDateIncomplete = false; this.writeValue(null); // Notify datepicker that a change has happened and emit `valueChange` this.notify(); this.showClearButton = false; } /** * @hidden */ triggerChange() { const value = this.kendoDate.value; const oneValuePresent = isPresent(value) !== isPresent(this.value); if (+value !== +this.value || oneValuePresent) { this.value = cloneDate(value); this.notify(); } } /** * @hidden */ notify() { this.ngZone.run(() => { this.showClearButton = this.value ? true : false; this.onControlChange(cloneDate(this.value)); this.valueChange.emit(cloneDate(this.value)); }); } /** * @hidden */ registerOnChange(fn) { this.onControlChange = fn; } /** * @hidden */ registerOnTouched(fn) { this.onControlTouched = fn; } /** * Focuses the DateInput component. * * @example * ```ts * _@Component({ * selector: 'my-app', * template: ` * <button (click)="dateinput.focus()">Focus date input</button> * <kendo-dateinput #dateinput></kendo-dateinput> * ` * }) * export class AppComponent { } * ``` */ focus() { this.kendoDate && this.kendoDate.focus(); } /** * Blurs the DateInput component. */ blur() { const input = this.inputElement; if (input) { input.blur(); } } /** * @hidden */ handleButtonClick(offset) { this.showClearButton = true; this.arrowDirection = Arrow.None; if (!this.isActive) { this.kendoDate.focus(); } this.kendoDate.modifyDateSegmentValue(offset); } initKendoDate() { const kendoDate = new DateInput(this.dateInput.nativeElement, { ...this.options, events: { valueChange: this.onWidgetValueChange.bind(this), inputEnd: this.onWidgetInputEnd.bind(this), focusEnd: this.onWidgetFocus.bind(this), blurEnd: this.onWidgetBlur.bind(this), keydown: this.onWidgetKeyDown.bind(this), } }); return kendoDate; } onWidgetValueChange() { this.triggerChange(); } onWidgetKeyDown() { this.kendoDateObject = this.kendoDate.dateObject; } onWidgetInputEnd() { this.updateIncompleteValidationStatus(); if (this.clearButton) { this.showClearButton = this.value || this.isDateIncomplete ? true : false; this.cdr.markForCheck(); } } onWidgetFocus(args) { this.isActive = true; if (hasObservers(this.onFocus)) { this.ngZone.run(() => { this.emitFocus(args.event); }); } else { this.emitFocus(args.event); } } onWidgetBlur(args) { this.isActive = false; if (hasObservers(this.onBlur) || requiresZoneOnBlur(this.ngControl)) { this.ngZone.run(() => { this.onControlTouched(); this.emitBlur(args.event); this.cdr.markForCheck(); }); } else { this.emitBlur(args.event); } } handleKeyDown(event) { // an event without keyCode is triggered when using Edge's autofill -> ignore it in the common package if (!isPresent(event.keyCode)) { event.stopImmediatePropagation(); } } verifyRange() { if (!isDevMode()) { return; } if (!isValidRange(this.min, this.max)) { throw new Error(`The max value should be bigger than the min. See ${MIN_DOC_LINK} and ${MAX_DOC_LINK}.`); } } verifyValue(value) { if (!isDevMode()) { return; } if (value && !(value instanceof Date)) { throw new Error(`The 'value' should be a valid JavaScript Date instance or null. Check ${VALUE_DOC_LINK} for possible resolution.`); } } intlChange() { this.kendoDate.setOptions(this.options, true); this.updateFormatSections(); } emitFocus(args) { this.onFocus.emit(); if (this.pickerService) { this.pickerService.onFocus.emit(args); } } emitBlur(args) { this.onBlur.emit(); if (this.pickerService) { this.pickerService.onBlur.emit(args); } } setSpinnerFill(spinner, fill, oldFill) { if (oldFill !== 'none') { this.renderer.removeClass(spinner, `k-button-${oldFill}`); this.renderer.removeClass(spinner, `k-button-${oldFill}-base`); } this.renderer.addClass(spinner, `k-button-${fill}`); this.renderer.addClass(spinner, `k-button-${fill}-base`); } setComponentClasses() { if (this.size !== 'none') { this.renderer.addClass(this.wrapper.nativeElement, getSizeClass('input', this.size)); } if (this.rounded !== 'none') { this.renderer.addClass(this.wrapper.nativeElement, getRoundedClass(this.rounded)); } if (this.fillMode !== 'none') { this.renderer.addClass(this.wrapper.nativeElement, getFillModeClass('input', this.fillMode)); } if (this.spinners && this.fillMode !== 'none') { this.setSpinnerFill(this.spinup.nativeElement, this.fillMode); this.setSpinnerFill(this.spindown.nativeElement, this.fillMode); } } setInputAttributes() { const attributesToRender = Object.assign({}, this.mutableAttributes, this.parsedAttributes); setHTMLAttributes(attributesToRender, this.renderer, this.dateInput.nativeElement, this.ngZone); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DateInputComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.IntlService }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: i0.Injector }, { token: i2.LocalizationService }, { token: i3.PickerService, optional: true }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DateInputComponent, isStandalone: true, selector: "kendo-dateinput", inputs: { focusableId: "focusableId", pickerType: "pickerType", clearButton: "clearButton", disabled: "disabled", readonly: "readonly", title: "title", tabindex: "tabindex", role: "role", ariaReadOnly: "ariaReadOnly", tabIndex: "tabIndex", isRequired: "isRequired", format: "format", formatPlaceholder: "formatPlaceholder", placeholder: "placeholder", steps: "steps", max: "max", min: "min", rangeValidation: "rangeValidation", autoCorrectParts: "autoCorrectParts", autoSwitchParts: "autoSwitchParts", autoSwitchKeys: "autoSwitchKeys", allowCaretMode: "allowCaretMode", autoFill: "autoFill", incompleteDateValidation: "incompleteDateValidation", twoDigitYearMax: "twoDigitYearMax", enableMouseWheel: "enableMouseWheel", value: "value", spinners: "spinners", isPopupOpen: "isPopupOpen", hasPopup: "hasPopup", size: "size", rounded: "rounded", fillMode: "fillMode", inputAttributes: "inputAttributes" }, outputs: { valueChange: "valueChange", valueUpdate: "valueUpdate", onFocus: "focus", onBlur: "blur" }, host: { properties: { "class.k-readonly": "this.readonly", "class.k-input": "this.wrapperClass", "class.k-dateinput": "this.wrapperClass", "class.k-disabled": "this.disabledClass" } }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => DateInputComponent), multi: true }, { provide: NG_VALIDATORS, useExisting: forwardRef(() => DateInputComponent), multi: true }, { provide: L10N_PREFIX, useValue: 'kendo.dateinput' }, { provide: KendoInput, useExisting: forwardRef(() => DateInputComponent) }, LocalizationService ], viewQueries: [{ propertyName: "dateInput", first: true, predicate: ["dateInput"], descendants: true, static: true }, { propertyName: "spinup", first: true, predicate: ["spinup"], descendants: true }, { propertyName: "spindown", first: true, predicate: ["spindown"], descendants: true }], exportAs: ["kendo-dateinput"], usesOnChanges: true, ngImport: i0, template: ` <ng-container kendoDateInputLocalizedMessages i18n-increment="kendo.dateinput.increment|The label for the **Increment** button in the DateInput" increment="Increase value" i18n-decrement="kendo.dateinput.decrement|The label for the **Decrement** button in the DateInput" decrement="Decrease value" i18n-clearTitle="kendo.dateinput.clearTitle|The title of the clear button" clearTitle="clear" > </ng-container> <input #dateInput class="k-input-inner" [attr.required]="isControlRequired ? '' : null" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" [attr.role]="role" [attr.aria-readonly]="ariaReadOnly" [id]="focusableId" [title]="title" [tabindex]="tabindex" [disabled]="disabled" [readonly]="readonly" [placeholder]="placeholder" [attr.aria-expanded]="isPopupOpen" [attr.aria-haspopup]="hasPopup" [kendoEventsOutsideAngular]="{ dragstart: handleDragAndDrop, drop: handleDragAndDrop }" [scope]="this" /> <span *ngIf="clearButton && showClearButton" class="k-clear-value" [attr.title]="localization.get('clearTitle')" role="button" tabindex="-1" (click)="resetInput()" (mousedown)="$event.preventDefault()" > <kendo-icon-wrapper name="x" [svgIcon]="xIcon" > </kendo-icon-wrapper> </span> <span *ngIf="spinners" class="k-input-spinner k-spin-button" (mousedown)="$event.preventDefault()"> <button #spinup tabindex="-1" class="k-spinner-increase k-button k-icon-button" [class.k-active]="arrowDirection === arrow.Up" (mousedown)="arrowDirection = arrow.Up" (mouseleave)="arrowDirection = arrow.None" (click)="handleButtonClick(1)" [title]="localization.get('increment')" [attr.aria-label]="localization.get('increment')" > <kendo-icon-wrapper name="caret-alt-up" [svgIcon]="caretAltUpIcon" innerCssClass="k-button-icon" > </kendo-icon-wrapper> </button> <button #spindown tabindex="-1" class="k-spinner-decrease k-button k-icon-button" (click)="handleButtonClick(-1)" [class.k-active]="arrowDirection === arrow.Down" (mousedown)="arrowDirection = arrow.Down" (mouseleave)="arrowDirection = arrow.None" [title]="localization.get('decrement')" [attr.aria-label]="localization.get('decrement')" > <kendo-icon-wrapper name="caret-alt-down" [svgIcon]="caretAltDownIcon" innerCssClass="k-button-icon" > </kendo-icon-wrapper> </button> </span> `, isInline: true, dependencies: [{ kind: "directive", type: DateInputLocalizedMessagesDirective, selector: "[kendoDateInputLocalizedMessages]" }, { kind: "directive", type: EventsOutsideAngularDirective, selector: "[kendoEventsOutsideAngular]", inputs: ["kendoEventsOutsideAngular", "scope"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DateInputComponent, decorators: [{ type: Component, args: [{ changeDetection: ChangeDetectionStrategy.OnPush, exportAs: 'kendo-dateinput', providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => DateInputComponent), multi: true }, { provide: NG_VALIDATORS, useExisting: forwardRef(() => DateInputComponent), multi: true }, { provide: L10N_PREFIX, useValue: 'kendo.dateinput' }, { provide: KendoInput, useExisting: forwardRef(() => DateInputComponent) }, LocalizationService ], selector: 'kendo-dateinput', template: ` <ng-container kendoDateInputLocalizedMessages i18n-increment="kendo.dateinput.increment|The label for the **Increment** button in the DateInput" increment="Increase value" i18n-decrement="kendo.dateinput.decrement|The label for the **Decrement** button in the DateInput" decrement="Decrease value" i18n-clearTitle="kendo.dateinput.clearTitle|The title of the clear button" clearTitle="clear" > </ng-container> <input #dateInput class="k-input-inner" [attr.required]="isControlRequired ? '' : null" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" [attr.role]="role" [attr.aria-readonly]="ariaReadOnly" [id]="focusableId" [title]="title" [tabindex]="tabindex" [disabled]="disabled" [readonly]="readonly" [placeholder]="placeholder" [attr.aria-expanded]="isPopupOpen" [attr.aria-haspopup]="hasPopup" [kendoEventsOutsideAngular]="{ dragstart: handleDragAndDrop, drop: handleDragAndDrop }" [scope]="this" /> <span *ngIf="clearButton && showClearButton" class="k-clear-value" [attr.title]="localization.get('clearTitle')" role="button" tabindex="-1" (click)="resetInput()" (mousedown)="$event.preventDefault()" > <kendo-icon-wrapper name="x" [svgIcon]="xIcon" > </kendo-icon-wrapper> </span> <span *ngIf="spinners" class="k-input-spinner k-spin-button" (mousedown)="$event.preventDefault()"> <button #spinup tabindex="-1" class="k-spinner-increase k-button k-icon-button" [class.k-active]="arrowDirection === arrow.Up" (mousedown)="arrowDirection = arrow.Up" (mouseleave)="arrowDirection = arrow.None" (click)="handleButtonClick(1)" [title]="localization.get('increment')" [attr.aria-label]="localization.get('increment')" > <kendo-icon-wrapper name="caret-alt-up" [svgIcon]="caretAltUpIcon" innerCssClass="k-button-icon" > </kendo-icon-wrapper> </button> <button #spindown tabindex="-1" class="k-spinner-decrease k-button k-icon-button" (click)="handleButtonClick(-1)" [class.k-active]="arrowDirection === arrow.Down" (mousedown)="arrowDirection = arrow.Down" (mouseleave)="arrowDirection = arrow.None" [title]="localization.get('decrement')" [attr.aria-label]="localization.get('decrement')" > <kendo-icon-wrapper name="caret-alt-down" [svgIcon]="caretAltDownIcon" innerCssClass="k-button-icon" > </kendo-icon-wrapper> </button> </span> `, standalone: true, imports: [DateInputLocalizedMessagesDirective, EventsOutsideAngularDirective, NgIf, IconWrapperComponent] }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i1.IntlService }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: i0.Injector }, { type: i2.LocalizationService }, { type: i3.PickerService, decorators: [{ type: Optional }] }]; }, propDecorators: { focusableId: [{ type: Input }], pickerType: [{ type: Input }], clearButton: [{ type: Input }], disabled: [{ type: Input }], readonly: [{ type: Input }, { type: HostBinding, args: ['class.k-readonly'] }], title: [{ type: Input }], tabindex: [{ type: Input }], role: [{ type: Input }], ariaReadOnly: [{ type: Input }], tabIndex: [{ type: Input }], isRequired: [{ type: Input }], format: [{ type: Input }], formatPlaceholder: [{ type: Input }], placeholder: [{ type: Input }], steps: [{ type: Input }], max: [{ type: Input }], min: [{ type: Input }], rangeValidation: [{ type: Input }], autoCorrectParts: [{ type: Input }], autoSwitchParts: [{ type: Input }], autoSwitchKeys: [{ type: Input }], allowCaretMode: [{ type: Input }], autoFill: [{ type: Input }], incompleteDateValidation: [{ type: Input }], twoDigitYearMax: [{ type: Input }], enableMouseWheel: [{ type: Input }], value: [{ type: Input }], spinners: [{ type: Input }], isPopupOpen: [{ type: Input }], hasPopup: [{ type: Input }], size: [{ type: Input }], rounded: [{ type: Input }], fillMode: [{ type: Input }], inputAttributes: [{ type: Input }], valueChange: [{ type: Output }], valueUpdate: [{ type: Output }], onFocus: [{ type: Output, args: ['focus'] }], onBlur: [{ type: Output, args: ['blur'] }], dateInput: [{ type: ViewChild, args: ['dateInput', { static: true }] }], wrapperClass: [{ type: HostBinding, args: ['class.k-input'] }, { type: HostBinding, args: ['class.k-dateinput'] }], disabledClass: [{ type: HostBinding, args: ['class.k-disabled'] }], spinup: [{ type: ViewChild, args: ['spinup', { static: false }] }], spindown: [{ type: ViewChild, args: ['spindown', { static: false }] }] } });