Bind an input with type datetime-local to a Date property in Angular 2

被刻印的时光 ゝ 提交于 2019-12-18 04:33:26

问题


It is possible to bind a component property of Date type to a HTML5 input with type set to datetime-local?

In my component I have a poperty:

public filterDateFrom: Date;

and in my template I have an input defined as:

<input type="datetime-local" [(ngModel)]="filterDateFrom" />

but binding doesn't work.


回答1:


Demo Plnkr

You can bind to a date using the following format: yyyy-MM-ddTHH:mm, which you can also get from date.toISOString().slice(0,16) (the slice removes the time portion after the 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);
    }
}

Keep in mind that date.toISOString() will return a date offset from local time. You can also construct the date string yourself:

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);
}

If you want to be able to bind the select to a Date model, you can use this to build a custom date component:

@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);
            }
        }
    }
}

Users of your component would bind to a Date model with two-way model binding:

@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();
    }
}

Or if you want to avoid custom tags, rewrite the component as a directive:

<input type="datetime-local" [(date)]="date" />

Demo Plnkr with Directive




回答2:


Now that its Spring 2017, DatePipe is shipped OOTB. You can achieve (one-way) binding by specifying format parameters to the pipe. For example:

<input type="datetime-local" [ngModel]="filterDateFrom | date:'yyyy-MM-ddTHH:mm'" />

Slight caveat is that you have to then manage the DOM --> model side of things to handle client changes to the control (unless I'm missing something!), but it seems a lot cleaner this way.


Update

Looks like I was indeed missing something!

Adding ngModelChange to the above should provide the DOM --> model side of the two-way binding process:

<input type="datetime-local" 
       [ngModel]="filterDateFrom | date:'yyyy-MM-ddTHH:mm'
       (ngModelChange)="filterDateFrom = $event" />



回答3:


I was looking into this problem as well and started to go down this examples road. However, you can use [(ngModel)] on an input of the type [date,datetime,datetime-local]. The key is to match the expected format the control is expecting. In this case it expects this format. Which also means the type that you bind to the control needs to be a string. I have provided an example plunker, that demonstrates how to use [(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);
  }
}



回答4:


Inspired by @ne1410s answer I ended doing something very similar but without losing the date type.

I used a pipe to declare the ngModel and call a method dateChanged just to return the conversion of the new Date in the ts.

html code:

<input type="datetime-local" [ngModel]="filterDateFrom | date:'yyyy-MM-ddTHH:mm'" (ngModelChange)="filterDateFrom = dateChanged($event)"/>

ts code:

 dateChanged(eventDate: string): Date | null {
   return !!eventDate ? new Date(eventDate) : null;
 }


来源:https://stackoverflow.com/questions/34546447/bind-an-input-with-type-datetime-local-to-a-date-property-in-angular-2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!