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?
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"/>
`
Vous devez convertir date object
au format input type="date"
qui est yyyy-mm-dd
, voici comment cela 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);
}
}
FormControls (à la fois basé sur un modèle et réactif) souscrivent des valeurs et écrivent des valeurs via des directives implémentant ControlValueAccessor
. Examinez la méthode appropriée selectValueAccessor , utilisée dans toutes les directives nécessaires. Les contrôles de saisie normaux (par exemple, _<input type="text">
_) ou les zones de texte sont gérés par le DefaultValueAccessor . Un autre exemple est CheckboxValueAccessor qui est appliqué aux contrôles d'entrée de case à cocher.
Le travail n'est pas compliqué du tout. Nous avons juste besoin d'implémenter un nouvel accesseur de valeur pour les contrôles de saisie de date.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 le DateValueAccessor
au multi-fournisseur _DATE_VALUE_ACCESSOR
_, de sorte que selectValueAccessor puisse le trouver.
La seule question est de savoir quel sélecteur devrait être utilisé. J'ai opté pour une solution opt-in.
Ici, DateValueAccessor sélectionne 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 l'implémentation par défaut.
Le sélecteur suivant activerait la fonction 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 sachez que cela pourrait casser les implémentations existantes qui reposent sur l'ancien comportement. Je choisirais donc la version opt-in!
Pour votre commodité, j'ai créé le projet angular-data-value-accessor
sur Github.
Un package NPM est également disponible:
_npm install --save angular-date-value-accessor
_
Ensuite, importez simplement le module via NgModule:
_// app.module.ts
import { DateValueAccessorModule } from 'angular-date-value-accessor';
@NgModule({
imports: [
DateValueAccessorModule
]
})
export class AppModule { }
_
Vous pouvez maintenant appliquer le "useValueAsDate" à vos contrôles de saisie de date.
Bien sûr, il y a une démonstration à: http://johanneshoppe.github.io/angular-date-value-accessor/
J'ai commencé à essayer d'implémenter la solution d'Ankit Singh et j'ai rencontré quelques problèmes de validation et de fuseau horaire. (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 chaîne et date à l'aide de chaînes de date au 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. Cela semble bien fonctionner pour moi, j'espère que quelqu'un d'autre trouvera cela utile.
Pour mon application Angular 2, j'ai lancé npm install --save moment, puis j'ai transformé la solution d'Ankit en wrapper 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;
}
}
Puis pour le HTML:
<input type="date" name="someDate" [(ngModel)]="ngDateModel.dateInput"/>
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>