@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,193 lines (1,188 loc) • 43.9 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* 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).
*
* ```html
* <kendo-dateinput/>
* ```
*
* @remarks
* Supported children components are: {@link DateInputCustomMessagesComponent}.
*/
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}`;
}
}
/**
* Specifies whether to render 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;
/**
* Specifies whether the component is disabled
* ([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).
*
* @default false
*/
disabled = false;
/**
* Specifies the read-only state of the DateInput
* ([see example]({% slug readonly_dateinput %})).
*
* @default false
*/
readonly = false;
/**
* Specifies the title of the input element of the DateInput.
*
* @default ""
*/
title = "";
/**
* Specifies the `tabIndex` property of the DateInput.
*
* @default 0
*/
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 %})).
*
* You can provide a string if a single format is going to be used regardless whether the input is focused or blurred.
* Alternatively, you can provide a FormatSettings object to display different formats when the component is focused or blurred by specifying 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 %}).
*/
set formatPlaceholder(format) {
this._formatPlaceholder = 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 %}).
* @default null
*/
placeholder = null;
/**
* Configures the incremental steps of the DateInput.
* For more information, refer to the article on
* [incremental steps]({% slug incrementalsteps_dateinput %}).
*/
steps = {};
/**
* Specifies the biggest date that is valid
* ([see example]({% slug dateranges_dateinput %})).
*
* @default 2099-12-31
*/
max = cloneDate(MAX_DATE);
/**
* Specifies the smallest date that is valid
* ([see example]({% slug dateranges_dateinput %})).
*
* @default 1900-1-1
*/
min = cloneDate(MIN_DATE);
/**
* Specifies whether to enforce the built-in min and max validators when validating a form.
* Set to `true` to enable validation for the `min` and `max` values.
*
* @default true
*/
rangeValidation = true;
/**
* Specifies if the component automatically corrects invalid date segments.
* When set to `true`, the component fixes invalid segments as you type.
*
* @default true
*/
autoCorrectParts = true;
/**
* Specifies if the component automatically moves to the next segment after you complete the current one.
* When set to `true`, focus moves to the next segment as soon as you finish typing the current segment.
*
* @default true
*/
autoSwitchParts = true;
/**
* Specifies custom keys that move focus to the next date format segment.
* Provide an array of strings to define which keys trigger the focus change.
*/
autoSwitchKeys = [];
/**
* Specifies if the component displays a blinking caret inside the DateInput when possible.
* Set to `true` to show a blinking caret for better visual feedback.
*
* @default false
*/
allowCaretMode = false;
/**
* Specifies whether to autofill the rest of the date to the current date when the component loses focus.
*
* @default false
*/
autoFill = false;
/**
* Specifies whether the built-in validation for incomplete dates is to be enforced when a form is being validated.
*
* @default false
*/
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.
* @default 68
*/
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 %}).
*
* @default false
*/
spinners = false;
/**
* @hidden
*/
isPopupOpen;
/**
* @hidden
*/
hasPopup;
/**
* Specifies the size of the component.
*
* @default medium
*
*/
set size(size) {
this.renderer.removeClass(this.wrapper.nativeElement, getSizeClass('input', this.size));
const newSize = size || DEFAULT_SIZE;
if (newSize !== 'none') {
this.renderer.addClass(this.wrapper.nativeElement, getSizeClass('input', newSize));
}
this._size = newSize;
}
get size() {
return this._size;
}
/**
* Specifies the border radius of the component.
* @default 'medium'
*/
set rounded(rounded) {
this.renderer.removeClass(this.wrapper.nativeElement, getRoundedClass(this.rounded));
const newRounded = rounded || DEFAULT_ROUNDED;
if (newRounded !== 'none') {
this.renderer.addClass(this.wrapper.nativeElement, getRoundedClass(newRounded));
}
this._rounded = newRounded;
}
get rounded() {
return this._rounded;
}
/**
* Specifies the fillMode of the component.
* @default 'solid'
*/
set fillMode(fillMode) {
this.renderer.removeClass(this.wrapper.nativeElement, getFillModeClass('input', this.fillMode));
const newFillMode = 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;
}
/**
* Specifies 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.
*
*/
focus() {
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 = { ...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 }]
}] } });