File

src/lib/dl-date-time-input/dl-date-time-input.directive.ts

Description

This directive allows the user to enter dates, using the keyboard, into an input box and angular will then store a date value in the model.

The input format(s), display format, and model format are independent and fully customizable.

Implements

ControlValueAccessor Validator

Metadata

Index

Methods
Inputs
Outputs
HostListeners
Accessors

Constructor

constructor(_renderer: Renderer2, _elementRef: ElementRef, _dateAdapter: DlDateAdapter<D>, _displayFormat: string, _inputFormats: string[])

Constructs a new instance of this directive. reference to the renderer. reference to this element. date adapter for the date type in the model. from DL_DATE_TIME_DISPLAY_FORMAT, which defines the format to use for a valid date/time value. from DL_DATE_TIME_INPUT_FORMATS, which defines the input formats that allowed as valid date/time values. NB: moment is always in strict parse mode for this directive.

Parameters :
Name Type Optional Description
_renderer Renderer2 No

reference to the renderer.

_elementRef ElementRef No

reference to this element.

_dateAdapter DlDateAdapter<D> No

date adapter for the date type in the model.

_displayFormat string No

from DL_DATE_TIME_DISPLAY_FORMAT, which defines the format to use for a valid date/time value.

_inputFormats string[] No

from DL_DATE_TIME_INPUT_FORMATS, which defines the input formats that allowed as valid date/time values. NB: moment is always in strict parse mode for this directive.

Inputs

dlDateTimeInputFilter
Type : boolean

Set a function used to determine whether or not the value entered by the user is allowed. a function that returns true if the value entered by the user is allowed, otherwise false.

Outputs

dateChange
Type : EventEmitter

Emits when a change event when date/time is selected or the value of the date/time picker changes.

HostListeners

blur

Format the input text using DL_DATE_TIME_DISPLAY_FORMAT and mark the control as touched.

change

Emit a change event when the value of the input changes.

input
Arguments : '$event.target.value'

Parse the user input into a possibly valid date. The model value is not set if the input is NOT one of the DL_DATE_TIME_INPUT_FORMATS. Value of the input control.

Parameters :
Name Optional Description
value No

Value of the input control.

Methods

_onBlur
_onBlur()
Decorators :
@HostListener('blur')

Format the input text using DL_DATE_TIME_DISPLAY_FORMAT and mark the control as touched.

Returns : void
_onChange
_onChange()
Decorators :
@HostListener('change')

Emit a change event when the value of the input changes.

Returns : void
_onInput
_onInput(value: string | null | undefined)
Decorators :
@HostListener('input', ['$event.target.value'])

Parse the user input into a possibly valid date. The model value is not set if the input is NOT one of the DL_DATE_TIME_INPUT_FORMATS. Value of the input control.

Parameters :
Name Type Optional Description
value string | null | undefined No

Value of the input control.

Returns : void

Accessors

dlDateTimeInputFilter
setdlDateTimeInputFilter(inputFilterFunction: (value: D | null) => void)

Set a function used to determine whether or not the value entered by the user is allowed. a function that returns true if the value entered by the user is allowed, otherwise false.

Parameters :
Name Type Optional Description
inputFilterFunction function No

a function that returns true if the value entered by the user is allowed, otherwise false.

Returns : void
value
getvalue()

Returns D value of the date/time input or undefined | null if no value is set.

Returns : D
setvalue(newValue: D | null | undefined)

Set the value of the date/time input to a value of D | undefined | null; the new value of the date/time input

Parameters :
Name Type Optional Description
newValue D | null | undefined No

the new value of the date/time input

Returns : void

This directive provides all of the user facing functionality to input a date and/or time using the keyboard. |

Model date types

Import the module corresponding to the desired data type of the date in the model.

  • Native JavaScript Date: import DlDateTimePickerDateModule
  • Moment Date: import DlDateTimePickerMomentModule
  • Milliseconds (local): import DlDateTimePickerNumberModule
  • String (local): import DlDateTimePickerStringModule

A DateAdapter is used to adapt the data type in the model to the number data type used internally by the date/time picker.

If you need a different data type than what is currently supported, you can extend DlDateAdapter<D> to provide the data type you need then override the DlDateAdapter provider in app.module.ts to use your new class.

providers: [{provide: DlDateAdapter, useClass: MyCustomDateAdapter}],

Display format

The display format is defined in the DL_DATE_TIME_DISPLAY_FORMAT token and is injected into this component to control the display format.

DL_DATE_TIME_DISPLAY_FORMAT defaults to moment's lll long date format. Override DL_DATE_TIME_DISPLAY_FORMAT if you do not like the default format.

{provide: DL_DATE_TIME_DISPLAY_FORMAT, useValue: '<what ever format you want goes here>'}

Input formats

This directive supports multiple input formats, as defined in the DL_DATE_TIME_INPUT_FORMATS token. When the user inputs a string value into a text box, this directive attempts to parse the input using one of the specified formats, in the order the format occur in the array.

Once one of the formats is able to parse the user input, the date is set in the model.

Nota bene For convenience DL_DATE_TIME_INPUT_FORMATS defaults to support multiple formats, which can dramatically slow down parsing performance. It can also result in successfully parsing a date using a format that is not appropriate for your use case.

Consider overriding the DL_DATE_TIME_INPUT_FORMATS token to only include the specific formats required by your project.

{provide: DL_DATE_TIME_INPUT_FORMATS, useValue: ['<input format zero>', ..., '<input format N>']}

See moment's parsing multiple formats page for more information on how these date formats are used.

import {Directive, ElementRef, EventEmitter, HostListener, Inject, Input, Output, Renderer2} from '@angular/core';
import {
  AbstractControl,
  ControlValueAccessor,
  NG_VALIDATORS,
  NG_VALUE_ACCESSOR,
  ValidationErrors,
  Validator,
  ValidatorFn,
  Validators,
} from '@angular/forms';
import moment from 'moment';
import {DL_DATE_TIME_DISPLAY_FORMAT, DL_DATE_TIME_INPUT_FORMATS, DlDateAdapter} from '../core/public-api';
import {DlDateTimeInputChange} from './dl-date-time-input-change';

/**
 *  This directive allows the user to enter dates, using the keyboard, into an input box and
 *  angular will then store a date value in the model.
 *
 *  The input format(s), display format, and model format are independent and fully customizable.
 */
@Directive({
  selector: 'input[dlDateTimeInput]',
  providers: [
    {provide: NG_VALUE_ACCESSOR, useExisting:  DlDateTimeInputDirective, multi: true},
    {provide: NG_VALIDATORS, useExisting:  DlDateTimeInputDirective, multi: true}
  ]
})
export class DlDateTimeInputDirective<D> implements ControlValueAccessor, Validator {

  /* tslint:disable:member-ordering */
  private _filterValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
    return (this._inputFilter || (() => true))(this._value) ?
      null : {'dlDateTimeInputFilter': {'value': control.value}};
  }
  private _inputFilter: (value: (D | null)) => boolean = () => true;
  private _isValid = true;
  private _parseValidator: ValidatorFn = (): ValidationErrors | null => {
    return this._isValid ?
      null : {'dlDateTimeInputParse': {'text': this._elementRef.nativeElement.value}};
  }
  private _changed: ((value: D) => void)[] = [];
  private _touched: (() => void)[] = [];
  private _validator = Validators.compose([this._parseValidator, this._filterValidator]);
  private _onValidatorChange: () => void = () => {};
  private _value: D | undefined = undefined;

  /**
   * Emits when a `change` event when date/time is selected or
   * the value of the date/time picker changes.
   **/
  @Output()
  readonly dateChange = new EventEmitter<DlDateTimeInputChange<D>>();

  /**
   * Constructs a new instance of this directive.
   * @param _renderer
   *  reference to the renderer.
   * @param _elementRef
   *  reference to this element.
   * @param _dateAdapter
   *  date adapter for the date type in the model.
   * @param _displayFormat
   *  from `DL_DATE_TIME_DISPLAY_FORMAT`, which defines the format to use for a valid date/time value.
   * @param _inputFormats
   *  from `DL_DATE_TIME_INPUT_FORMATS`, which defines the input formats that allowed as valid date/time values.
   *  NB: moment is always in strict parse mode for this directive.
   */
  constructor(
    private _renderer: Renderer2,
    private _elementRef: ElementRef,
    private _dateAdapter: DlDateAdapter<D>,
    @Inject(DL_DATE_TIME_DISPLAY_FORMAT) private readonly _displayFormat: string,
    @Inject(DL_DATE_TIME_INPUT_FORMATS) private readonly _inputFormats: string[]
  ) {}

  /**
   * Set a function used to determine whether or not the `value` entered by the user is allowed.
   * @param inputFilterFunction
   *   a function that returns `true` if the `value` entered by the user is allowed, otherwise `false`.
   */
  @Input()
  set dlDateTimeInputFilter(inputFilterFunction: (value: D | null) => boolean) {
    this._inputFilter = inputFilterFunction || (() => true);
    this._onValidatorChange();
  }

  /* tslint:enable:member-ordering */

  /**
   * Returns `D` value of the date/time input or `undefined` | `null` if no value is set.
   **/
  get value(): D {
    return this._value;
  }

  /**
   * Set the value of the date/time input to a value of `D` | `undefined` | `null`;
   * @param newValue
   *  the new value of the date/time input
   */

  set value(newValue: D | null | undefined) {
    if (newValue !== this._value) {
      this._value = newValue;
      this._changed.forEach(onChanged => onChanged(this._value));
    }
  }

  /**
   * Emit a `change` event when the value of the input changes.
   */
  @HostListener('change') _onChange() {
    this.dateChange.emit(new DlDateTimeInputChange(this._value));
  }

  /**
   * Format the input text using {@link DL_DATE_TIME_DISPLAY_FORMAT} and mark the control as touched.
   */
  @HostListener('blur') _onBlur() {
    if (this._value) {
      this._setElementValue(this._value);
    }
    this._touched.forEach(onTouched => onTouched());
  }

  /**
   * Parse the user input into a possibly valid date.
   * The model value is not set if the input is NOT one of the {@link DL_DATE_TIME_INPUT_FORMATS}.
   * @param value
   *   Value of the input control.
   */
  @HostListener('input', ['$event.target.value']) _onInput(value: string | null | undefined): void {
    const testDate = value === null || value === undefined || value === ''
      ? undefined
      : moment(value, this._inputFormats, true);

    this._isValid = testDate && testDate.isValid();
    this.value = this._isValid ? this._dateAdapter.fromMilliseconds(testDate.valueOf()) : undefined;
  }

  /**
   * @internal
   */
  private _setElementValue(value: D) {
    if (value !== null && value !== undefined) {
      this._renderer.setProperty(this._elementRef.nativeElement, 'value', moment(value).format(this._displayFormat));
    }
  }

  /**
   * @internal
   */
  registerOnChange(onChange: (value: any) => void): void {
    this._changed.push(onChange);
  }

  /**
   * @internal
   */
  registerOnTouched(onTouched: () => void): void {
    this._touched.push(onTouched);
  }

  /**
   * @internal
   */
  registerOnValidatorChange(validatorOnChange: () => void): void {
    this._onValidatorChange = validatorOnChange;
  }

  /**
   * @internal
   */
  setDisabledState(isDisabled: boolean): void {
    this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
  }

  /**
   * @internal
   */
  validate(control: AbstractControl): ValidationErrors | null {
    return this._validator(control);
  }

  /**
   * @internal
   */
  writeValue(value: D): void {
    this._isValid = true;
    this.value = value;
    this._setElementValue(value);
  }
}

results matching ""

    No results matching ""