Sharing Top Content from the Angular-sphere.

Angular 2: How to use date input controls with Angular Forms

  • We just need to implement a new value accessor for date input controls.
  • Even if myBirtday contains a valid date, the date input control is not rendering the value at all.
  • According to the specification, date input controls are based on strings.
  • Angular 2: How to use date input controls with Angular Forms
  • Now you can apply the “useValueAsDate” to your date input controls.

Working with forms is pretty easy in Angular 2.
You just need to decide between Template-Driven and Reactive Forms and you are ready to start with some bindings and validation. The following code shows a two-way data binding with ngModel against a property of type string:

@JohannesHoppe: #Angular2: How to use <input type=”date”> in #Angular Forms #angularjs #forms…

Working with forms is pretty easy in Angular 2. You just need to decide between Template-Driven and Reactive Forms and you are ready to start with some bindings and validation. The following code shows a two-way data binding with

ngModel

against a property of type

string

But there is one problem to tackle: models of type

You might wonder, because HTML5 date input controls are not working as expected:

Even if

myBirtday

contains a valid date, the date input control is not rendering the value at all. In fact, we are supposed to set a string that is representing a full-date as defined in RFC 3339. The same string is written back to the model, when changes have been made, e.g. “2016-10-13”. This behavior is specified in the W3C HTML language reference for

inputEl.value

. According to the specification, date input controls are based on strings. So what can we do to keep the Date type?

Let’s review the possible solutions:

This would be a clean and extendable solution, but it might lead to more code than required for the given use-case.

But do we really want to bloat our “business code layer” with boilerplate code?

It turns out, that date input control has another, not that well-known property:

inputEl.valueAsDate

! The

attribute represents the value (still a string) of the element, interpreted as a date. This is exactly what we need. Now we only need to convince Angular to use this property, instead of

Fortunately Angular 2 is very expansible here. FormControls (both template-driven and reactive) subscribe for values and write values via Directives that implement

. Take a look at the relevant method selectValueAccessor, which is used in all necessary directives. Normal input controls (e.g.

) or textareas are handled by the DefaultValueAccessor. Another example is the CheckboxValueAccessor which is applied to checkbox input controls.

The job isn’t complicated at all. We just need to implement a new value accessor for date input controls.

is a nice name:

// date-value-accessor.ts import { Directive, ElementRef, HostListener, Renderer, forwardRef } from ‘@angular/core’; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from ‘@angular/forms’; export const DATE_VALUE_ACCESSOR: any = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => DateValueAccessor), multi: true }; /** * The accessor for writing a value and listening to changes on a date input element * * ### Example * `` */ @Directive({ selector: ‘[useValueAsDate]’, providers: [DATE_VALUE_ACCESSOR] }) export class DateValueAccessor implements ControlValueAccessor { @HostListener(‘input’, [‘$event.target.valueAsDate’]) onChange = (_: any) => { }; @HostListener(‘blur’, []) onTouched = () => { }; constructor(private _renderer: Renderer, private _elementRef: ElementRef) { } writeValue(value: Date): void { this._renderer.setElementProperty(this._elementRef.nativeElement, ‘valueAsDate’, value); } registerOnChange(fn: (_: any) => void): void { this.onChange = fn; } registerOnTouched(fn: () => void): void { this.onTouched = fn; } setDisabledState(isDisabled: boolean): void { this._renderer.setElementProperty(this._elementRef.nativeElement, ‘disabled’, isDisabled); } }

We attach the

, so that selectValueAccessor can find it.

The only question is, which selector should be used. I decided for an opt-in solution.

Here the DateValueAccessor selects on the attribute “useValueAsDate”.

It is also possible to fix the default implementation.

The following selector would activate the feature magically.

// this selector changes the previous behavior silently and might break existing code selector: ‘input[type=date][formControlName],input[type=date][formControl],input[type=date][ngModel]’

But please be aware, that this might break existing implementations that rely of the old behaviour. So I would go for the opt-in version!

For your convenience, I created the project

on Github.

There is also a NPM package available:

Then just import the module via NgModule:

// app.module.ts import { DateValueAccessorModule } from ‘angular-date-value-accessor’; @NgModule({ imports: [ DateValueAccessorModule ] }) export class AppModule { }

Now you can apply the “useValueAsDate” to your date input controls.

Angular 2.0 wird in naher Zukunft fertiggestellt sein. Es gibt es bereits regelmäßige Vorabversionen für interessierte Entwickler. Das Angular-Team hat sich entschieden, alte Zöpfe rigoros abzuschneiden und ein komplett überarbeitetes Framework zu entwickeln. Die neue Version bricht mit bestehenden Konzepten – was für viel Aufregung gesorgt hat. Die Template-Syntax ist neu, und man setzt nun Komponenten statt Controller ein. Auch der Einsatz von TypeScript rüttelt am Althergebrachten.

Angular 2: How to use date input controls with Angular Forms

Comments are closed, but trackbacks and pingbacks are open.