57 votes

Angular2: Comment utiliser un objet Date en JavaScript avec la liaison bidirectionnelle NgModel

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

JS, ce code lance la variable employee du 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 telles que le prénom sont affichées correctement. Mais pour la date, je viens d'avoir:

 mm/dd/yyyy
 

Dans l'élément d'entrée, ce qui devrait être une date.

Comment puis-je faire ceci?

112voto

Ankit Singh Points 15545

Mise à JOUR:

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

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

`


Vieille Réponse:

PLUNKER

Vous avez besoin de convertir date object dans la input type="date" format yyyy-mm-dd, c'est la façon dont 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);
  }
}

20voto

mbraint Points 381

Lire les tuyaux et ngModel et ma décision:

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

8voto

Johannes Hoppe Points 11

FormControls (à la fois modèle axé sur la et réactif) abonnez-vous pour les valeurs et écrire des valeurs via des Directives qui mettent en oeuvre ControlValueAccessor. Jetez un oeil à la méthode selectValueAccessor, qui est utilisé dans toutes les directives nécessaires. Normal contrôles de saisie (par exemple, <input type="text">) ou de ces zones de texte sont traitées par le DefaultValueAccessor. Un autre exemple est la CheckboxValueAccessor qui est appliqué à la case de contrôles de saisie.

Le travail n'est pas compliqué du tout. Nous avons juste besoin de mettre en œuvre une nouvelle valeur de l'accesseur pour la date de contrôles de saisie.
DateValueAccessor est un joli 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 attachons de l' DateValueAccessor de la multi-fournisseur DATE_VALUE_ACCESSOR, de sorte que selectValueAccessor pouvez le trouver.

La seule question est, qui sélecteur doit être utilisé. J'ai décidé pour 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 corriger le défaut de mise en œuvre.
Le sélecteur suivant activer la fonctionnalité comme par magie.

// 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 s'il vous plaît être conscient que cela peut casser implémentations existantes qui utilisent de l'ancien comportement. Donc je pencherais pour l'opt-in version!

C'est tout le MNP et Github

Pour votre commodité, j'ai créé le projet angular-data-value-accessor sur Github.
Il y a aussi un MNP forfait disponible:

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

Ensuite, il suffit d'importer le module via NgModule:

// app.module.ts

import { DateValueAccessorModule } from 'angular-date-value-accessor';

@NgModule({
  imports: [
    DateValueAccessorModule
  ]
})
export class AppModule { }

Maintenant, vous pouvez appliquer la "useValueAsDate" votre date de contrôles de saisie.

Démo

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

3voto

boylec1986 Points 79

J'ai commencé à essayer de mettre en œuvre Ankit Singh solution et a couru à quelques problèmes avec la validation et le fuseau horaire de trucs. (Même après avoir essayé les suggestions dans la section 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 le format ISO8601 date de chaînes. J'ai eu d'excellents résultats dans le passé à l'aide de moment.js donc, ce n'était pas une décision difficile à prendre. Semble bien fonctionner pour moi, j'espère que quelqu'un d'autre trouve cela utile.

Pour ma Angulaire 2 app, j'ai couru npm install --enregistrer instant puis tourna Ankit de la solution dans un wrapper autour d'un js Date objet:

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"/>

2voto

stijn.aerts Points 2695

Fixé 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>
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X