Angular2: Comment utiliser JavaScript Data Object avec NgModel à deux voies

Je travaille avec Angular 2 et j'ai ce code:

JS, ce code lance la variable d'employé pour le modèle:

handleEmployee(employee : Employee){ this.employee = employee; this.employee.startDate = new Date('2005/01/01'); console.log(this.employee); } 

Modèle:

 ... <div> <label>Start date: </label> <input [(ngModel)]="employee.startDate" type="date" name="startDate"/> </div> <div> ... 

D'autres données comme le prénom sont affichées correctement. Mais pour la date où je viens d'avoir:

 mm/dd/yyyy 

Dans l'élément de saisie, qui devrait être une date.

Comment puis-je faire ceci?

METTRE À JOUR:

Lorsque j'ai écrit cette réponse, DatePipe n'existait pas, maintenant vous pouvez le faire

 <input [ngModel]="startDate | date:'yyyy-MM-dd'" (ngModelChange)="startDate = $event" type="date" name="startDate"/> 

`


Ancienne réponse:

PLUNKER

Vous devez convertir l' date object dans le format input type="date" format input type="date" qui est yyyy-mm-dd , c'est ainsi qu'il fonctionnera

Modèle:

 <input [(ngModel)]="humanDate" type="date" name="startDate"/> 

Composant (TS):

 export class App { startDate: any; constructor() { this.startDate = new Date(2005, 1, 4); } set humanDate(e){ e = e.split('-'); let d = new Date(Date.UTC(e[0], e[1]-1, e[2])); this.startDate.setFullYear(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()); } get humanDate(){ return this.startDate.toISOString().substring(0, 10); } } 

Lire les canaux et ngModel et ma description:

 <input type="date" class="form-control" id="myDate" [ngModel]="myDate | date:'y-MM-dd'" (ngModelChange)="myDate = $event" name="birthday"> 

FormControls (à la fois pilotés par un modèle et réactifs) s'abonnent à des valeurs et écrivent des valeurs via des directives qui implémentent ControlValueAccessor . Jetez un oeil à la méthode appropriée selectValueAccessor , qui est utilisé dans toutes les directives nécessaires. Les contrôles d'entrée normal (p <input type="text"> Ex. <input type="text"> ) ou les zones de texte sont gérés par l'administrateur DefaultValueAccessor . Un autre exemple est l' CheckboxValueAccessor qui est appliqué aux contrôles d'entrée de la case à cocher.

Le travail n'est pas compliqué du tout. Il suffit d'implémenter un nouvel accesseur de valeur pour les contrôles d'entrée de date.
DateValueAccessor est un bon nom:

 // 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 * `<input type="date" name="myBirthday" ngModel useValueAsDate>` */ @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); } } 

Nous DATE_VALUE_ACCESSOR au multi-fournisseur DATE_VALUE_ACCESSOR , afin que selectValueAccessor puisse le trouver.

La seule question est de savoir quel sélecteur doit être utilisé. J'ai décidé d'une solution opt-in.
Ici, le DateValueAccessor sélectionne sur l'attribut "useValueAsDate".

 <input type="date" name="myBirthday" ngModel useValueAsDate> OR <input type="date" name="myBirthday" [(ngModel)]="myBirthday" useValueAsDate> OR <input type="date" formControlName="myBirthday" useValueAsDate> 

Il est également possible de réparer l'implémentation par défaut.
Le sélecteur suivant active la fonction magiquement.

 // 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]' 

Mais soyez conscient que cela risque de briser les implémentations existantes qui dépendent de l'ancien comportement. Je voudrais donc utiliser la version opt-in!

Tout est sur NPM et Github

Pour votre commodité, j'ai créé le projet angular-data-value-accessor sur Github.
Il existe également un paquet NPM disponible:

 npm install --save angular-date-value-accessor 

Ensuite, importez le module via NgModule:

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

Maintenant, vous pouvez appliquer le "useValueAsDate" à vos contrôles d'entrée de date.

Démonstration

Bien sûr, il existe une démo à: http://johanneshoppe.github.io/angular-date-value-accessor/

J'ai commencé à essayer de mettre en œuvre la solution d'Ankit Singh et j'ai couru quelques problèmes de validation et de fuseau horaire. (Même après avoir essayé les suggestions dans la section de commentaire de cette réponse)

Au lieu de cela, j'ai choisi d'utiliser moment.js pour gérer la transformation entre la chaîne et la date en utilisant les chaînes de date du format ISO8601. J'ai eu d'excellents résultats dans le passé en utilisant moment.js donc ce n'était pas une décision difficile. Je semble bien fonctionner pour moi, j'espère que quelqu'un d'autre le trouve utile.

Pour mon application Angular 2, j'ai lancé npm install –save moment puis j'ai transformé la solution Ankit en enveloppe autour d'un objet js Date:

 import * as moment from 'moment'; export class NgDate { date: any; constructor() { this.date = new Date(); } set dateInput(e) { if (e != "") { var momentDate = moment(e, moment.ISO_8601).toDate(); this.date = momentDate; } else { this.date = null; } } get dateInput() { if(this.date == null) { return ""; } var stringToReturn = moment(this.date).format().substring(0, 10); return stringToReturn; } } 

Ensuite, pour le HTML:

 <input type="date" name="someDate" [(ngModel)]="ngDateModel.dateInput"/> 

L'a corrigé avec ce code:

 handleEmployee(employee : Employee){ this.employee = employee; let dateString : string = employee.startDate.toString(); let days : number = parseInt(dateString.substring(8, 10)); let months : number = parseInt(dateString.substring(5, 7)); let years : number = parseInt(dateString.substring(0, 5)); let goodDate : Date = new Date(years + "/" + months + "/" + days); goodDate.setDate(goodDate.getDate() + 2); this.date = goodDate.toISOString().substring(0, 10); } 

Html:

 <div> <label>Start date: </label> <input [(ngModel)]="date" type="date" name="startDate"/> </div>