将类型为 datetime-local 的输入绑定到 Angular 2 中的 Date 属性

Posted

技术标签:

【中文标题】将类型为 datetime-local 的输入绑定到 Angular 2 中的 Date 属性【英文标题】:Bind an input with type datetime-local to a Date property in Angular 2 【发布时间】:2016-04-05 10:14:48 【问题描述】:

可以将 Date 类型的组件属性绑定到类型设置为 datetime-localhtml5 输入?

在我的组件中,我有一个属性:

public filterDateFrom: Date;

在我的模板中,我有一个输入定义为:

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

但绑定不起作用。

【问题讨论】:

你试过去掉ng-model周围的[]吗?常见的绑定是ng-model="nameOfTheVarFromscopeOrPropertie" 【参考方案1】:

Demo Plnkr

您可以使用以下格式绑定到日期:yyyy-MM-ddTHH:mm,您也可以从 date.toISOString().slice(0,16) 获取(切片删除分钟后的时间部分)。

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

请记住,date.toISOString() 将返回与本地时间的日期偏移量。你也可以自己构造日期字符串:

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

如果您希望能够将 select 绑定到 Date 模型,您可以使用它来构建自定义日期组件:

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

您的组件的用户将通过双向模型绑定绑定到 Date 模型:

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

或者如果你想避免自定义标签,将组件重写为指令:

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

Demo Plnkr with Directive

【讨论】:

它可以工作,但是在绑定它(使用指令)之后,单击控件上的向上和向下箭头无法正常工作 - 当我选择了一个小时子字段时,单击向上箭头增加小时 +2 而不是 +1,当我选择了分钟子字段时,单击向上箭头会增加分钟 +1 和小时 +1 在哪个设备/浏览器上? Windows(桌面)上的 Google Chrome 47.0 固定解析逻辑 - 请参阅更新的 plnkr。 toDateString() 和 parseDateString() 应该是互补的:第一个将日期格式化为 yyyy-MM-ddTHH:mm 格式,第二个将其解析回 Date 对象。 您的组件看起来不错,但是当值被延迟加载时,您将如何更新该值?在稍后阶段通过 ngModel 设置时,该值显示为空。您可以通过将 date = 包装在 setTimeout 中来尝试此操作【参考方案2】:

现在是 2017 年春季,DatePipe OOTB 发货。您可以通过为管道指定格式参数来实现(单向)绑定。例如:

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

需要注意的是,你不能使用这种技术的双向绑定,你必须使用数据管道的一种绑定,然后管理 DOM 以对更改事件进行建模以处理客户端对控件的更改(除非我'我错过了一些东西!),但这样看起来更干净。


更新

看来我确实错过了什么!

在上面添加ngModelChange应该提供DOM-->双向绑定过程的模型端:

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

【讨论】:

我喜欢这种方法,但这对我来说有一个缺点:filterDateFrom 是 Date 类型,但 (ngModelChange)="filterDateFrom = $event" 分配了一个字符串。 (因此时区也关闭了) @ne1410s 我尝试了您的示例,但我需要显示 LongTime 格式 24 小时 我认为这是最好的答案!我创建了一个自定义函数来将filterDateFrom 转换为日期对象,而不是(ngModelChange)="filterDateFrom = $event"(ngModelChange)="setDateFrom($event)",函数类似于setDateFrom(e: string) filterDateFrom = new Date(e) (当日期无效时我也处理过if (e.trim() !== "")【参考方案3】:

我也在研究这个问题,并开始沿着这条示例之路走下去。但是,您可以在 [date,datetime,datetime-local] 类型的输入上使用 [(ngModel)]。关键是要匹配控件所期望的预期格式。在这种情况下,它需要this format。这也意味着您绑定到控件的类型必须是字符串。我提供了一个示例plunker,演示了如何使用 [(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);
  

【讨论】:

@Dan Simon 你的绑定属性不应该用下划线命名为'_dateTimeLocal'吗? @Pascal - 我想我错过了你的问题的一些背景。我猜你的意思是由于编码风格约定,下划线不应该在那里?也许,我没有跟上最好的 JS 编码实践,我倾向于让我所有的私有变量都以下划线开头。如果您从功能的角度询问,代码按预期运行,可以从我的答案中的 plunker 链接查看和运行。 这与风格无关。您的绑定表达式 dateTimeLocal 绑定到 this._dateTimeLocal = new Date();其中有一个下划线。我不明白为什么这会起作用!? @Pascal:啊,好吧,我想我明白混乱的来源。如您所知,C# 最简单的翻译是字符串类型的“dateTimeLocal”是属性,而 DateTime 类型的“_dateTimeLocal”是字段。 Typescript 支持Accessors,这就是“dateTimeLocal”的来源,请注意上面粘贴的代码底部似乎是函数的“get”和“set”关键字,这是 TypeScript 语法。我这样做是因为 HTML 控件不是 DateTime 而是 String,所以 Accessors 会处理它。 啊,我不知道 dateTimeLocal 是一个吸气剂。还没有完全向下滚动;-) 现在我明白了。从私有类字段中获取值。【参考方案4】:

受@ne1410s 回答的启发,我最终做了一些非常相似的事情,但没有丢失日期类型。

我使用管道声明ngModel并调用方法dateChanged只是为了返回ts中新日期的转换。

html代码:

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

ts 代码:

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

【讨论】:

以上是关于将类型为 datetime-local 的输入绑定到 Angular 2 中的 Date 属性的主要内容,如果未能解决你的问题,请参考以下文章

React JSX 将最小日期时间添加到 datetime-local 输入

如何设置 HTML5 输入类型 =“datetime-local”的样式 [重复]

如何显示输入类型 =“datetime-local”的值?

如何区分 datetime-local 类型的部分填充或无效输入与空输入?

将 datetime-local 类型的表单数据发布到 sql 表 datetime 字段

无法将 <input type="datetime-local" /> 的秒值设置为 0