Il est possible de lier une propriété de composant de type Date à une entrée HTML5 avec un type défini sur datetime-local
?
Dans mon composant j'ai une poperty:
public filterDateFrom: Date;
et dans mon modèle, j'ai une entrée définie comme:
<input type="datetime-local" [(ngModel)]="filterDateFrom" />
mais la liaison ne fonctionne pas.
Vous pouvez vous lier à une date en utilisant le format suivant: yyyy-MM-ddTHH:mm
, Que vous pouvez également obtenir à partir de date.toISOString().slice(0,16)
(la tranche supprime la portion de temps après les minutes).
@Component({
selector: 'app',
template: `<input type="datetime-local" [value]="date"
(change)="date=$event.target.value" /> {{date}}`
})
export class AppComponent {
date: string;
constructor() {
this.date = new Date().toISOString().slice(0, 16);
}
}
Gardez à l'esprit que date.toISOString()
renverra un décalage de date par rapport à l'heure locale. Vous pouvez également construire vous-même la chaîne de date:
private toDateString(date: Date): string {
return (date.getFullYear().toString() + '-'
+ ("0" + (date.getMonth() + 1)).slice(-2) + '-'
+ ("0" + (date.getDate())).slice(-2))
+ 'T' + date.toTimeString().slice(0,5);
}
Si vous souhaitez pouvoir lier la sélection à un modèle Date
, vous pouvez l'utiliser pour créer un composant de date personnalisé:
@Component({
selector: 'my-date',
events: ['dateChange'],
template: `<input type="datetime-local" [value] = "_date"
(change) = "onDateChange($event.target.value)" />`
})
export class MyDate{
private _date: string;
@Input() set date(d: Date) {
this._date = this.toDateString(d);
}
@Output() dateChange: EventEmitter<Date>;
constructor() {
this.date = new Date();
this.dateChange = new EventEmitter();
}
private toDateString(date: Date): string {
return (date.getFullYear().toString() + '-'
+ ("0" + (date.getMonth() + 1)).slice(-2) + '-'
+ ("0" + (date.getDate())).slice(-2))
+ 'T' + date.toTimeString().slice(0,5);
}
private parseDateString(date:string): Date {
date = date.replace('T','-');
var parts = date.split('-');
var timeParts = parts[3].split(':');
// new Date(year, month [, day [, hours[, minutes[, seconds[, ms]]]]])
return new Date(parts[0], parts[1]-1, parts[2], timeParts[0], timeParts[1]); // Note: months are 0-based
}
private onDateChange(value: string): void {
if (value != this._date) {
var parsedDate = this.parseDateString(value);
// check if date is valid first
if (parsedDate.getTime() != NaN) {
this._date = value;
this.dateChange.emit(parsedDate);
}
}
}
}
Les utilisateurs de votre composant se lieraient à un modèle Date
avec une liaison de modèle bidirectionnelle:
@Component({
selector: 'my-app',
directives: [MyDate],
template: '<my-date [(date)]="date"></my-date> {{date}}'
})
export class AppComponent {
@Input() date: Date;
constructor() {
this.date = new Date();
}
}
Ou si vous voulez éviter les balises personnalisées, réécrivez le composant en tant que directive:
<input type="datetime-local" [(date)]="date" />
Maintenant que son printemps 2017, DatePipe
est expédié OOTB. Vous pouvez obtenir une liaison (unidirectionnelle) en spécifiant des paramètres de format pour le tuyau. Par exemple:
<input type="datetime-local" [ngModel]="filterDateFrom | date:'yyyy-MM-ddTHH:mm'" />
Une légère mise en garde est que vous devez ensuite gérer le côté DOM -> modèle des choses pour gérer les modifications clientes du contrôle (sauf si je manque quelque chose!), Mais cela semble beaucoup plus propre de cette façon.
On dirait qu'il me manquait bien quelque chose!
L'ajout de ngModelChange
à ce qui précède devrait fournir le côté modèle DOM -> du processus de liaison bidirectionnelle:
<input type="datetime-local"
[ngModel]="filterDateFrom | date:'yyyy-MM-ddTHH:mm'
(ngModelChange)="filterDateFrom = $event" />
J'examinais également ce problème et j'ai commencé à suivre cette voie d'exemples. Cependant, vous pouvez utiliser [(ngModel)] sur une entrée du type [date, datetime, datetime-local]. La clé est de faire correspondre le format attendu que le contrôle attend. Dans ce cas, il attend ce format . Ce qui signifie également que le type que vous liez au contrôle doit être une chaîne. J'ai fourni un exemple plunker , qui montre comment utiliser [(ngModel)].
import { Component } from 'angular2/core';
@Component({
selector: 'my-app',
template: `
<form>
<input type="datetime-local" [(ngModel)]="dateTimeLocal"><br />
{{dateTimeLocal}}
</form>
`
})
export class AppComponent {
private _dateTimeLocal: Date;
constructor() {
this._dateTimeLocal = new Date();
}
private parseDateToStringWithFormat(date: Date): string {
let result: string;
let dd = date.getDate().toString();
let mm = (date.getMonth() + 1).toString();
let hh = date.getHours().toString();
let min = date.getMinutes().toString();
dd = dd.length === 2 ? dd : "0" + dd;
mm = mm.length === 2 ? mm : "0" + mm;
hh = hh.length === 2 ? hh : "0" + hh;
min = min.length === 2 ? min : "0" + min;
result = [date.getFullYear(), '-', mm, '-', dd, 'T', hh, ':', min].join('');
return result;
}
public set dateTimeLocal(v: string) {
let actualParsedDate = v ? new Date(v) : new Date();
let normalizedParsedDate = new Date(actualParsedDate.getTime() + (actualParsedDate.getTimezoneOffset() * 60000));
this._dateTimeLocal = normalizedParsedDate;
}
public get dateTimeLocal(): string {
return this.parseDateToStringWithFormat(this._dateTimeLocal);
}
}
Inspiré par la réponse de @ ne1410s, j'ai fini par faire quelque chose de très similaire mais sans perdre le type de date.
J'ai utilisé un canal pour déclarer le ngModel
et appeler une méthode dateChanged
juste pour renvoyer la conversion de la nouvelle date dans le ts
.
code HTML:
<input type="datetime-local" [ngModel]="filterDateFrom | date:'yyyy-MM-ddTHH:mm'" (ngModelChange)="filterDateFrom = dateChanged($event)"/>
code ts:
dateChanged(eventDate: string): Date | null {
return !!eventDate ? new Date(eventDate) : null;
}