Angular2:如何使用带有NgModel双向绑定的JavaScript Date Object

时间:2016-05-05 16:10:46

标签: javascript angular

我正在使用Angular 2,我有这段代码:

JS,此代码启动模板的employee变量:

handleEmployee(employee : Employee){
        this.employee = employee;
        this.employee.startDate = new Date('2005/01/01');
        console.log(this.employee);
    }

模板:

...
<div>
    <label>Start date: </label>
    <input [(ngModel)]="employee.startDate" type="date" name="startDate"/>
  </div>
  <div>
...

正确显示firstname等其他数据。但是到了我得到的日期:

mm/dd/yyyy

在input元素中,应该是日期。

我该怎么做?

7 个答案:

答案 0 :(得分:86)

UPDATE:

当我写这个答案DatePipe不存在时,现在你可以这样做

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

`

旧答案:

PLUNKER

您需要转换date object input type="date"格式的yyyy-mm-dd,这是它的工作原理

<强>模板:

<input [(ngModel)]="humanDate" type="date" name="startDate"/>

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

答案 1 :(得分:18)

阅读pipesngModel 和我的决定:

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

答案 2 :(得分:8)

FormControls(模板驱动和被动)通过实现ControlValueAccessor的指令订阅值和写入值。看一下相关方法selectValueAccessor,它在所有必要的指令中使用。正常输入控件(例如<input type="text">)或textareas由DefaultValueAccessor处理。另一个例子是CheckboxValueAccessor,它应用于复选框输入控件。

工作并不复杂。我们只需要为日期输入控件实现一个新的值访问器 DateValueAccessor是一个很好的名字:

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

我们将DateValueAccessor附加到多提供商DATE_VALUE_ACCESSOR,以便selectValueAccessor可以找到它。

唯一的问题是,应该使用哪个选择器。我决定选择加入解决方案 这里DateValueAccessor选择属性“useValueAsDate”。

<input type="date" name="myBirthday" ngModel useValueAsDate>

OR

<input type="date" name="myBirthday" [(ngModel)]="myBirthday" useValueAsDate>

OR

<input type="date" formControlName="myBirthday" useValueAsDate>

也可以修复默认实现 以下选择器会神奇地激活该功能。

// 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]'

但请注意,这可能会破坏依赖旧行为的现有实现。所以我会去选择加入版本!

一切都在NPM和Github上

为方便起见,我在Github上创建了项目angular-data-value-accessor 还有一个NPM包:

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

然后只需通过NgModule导入模块:

// app.module.ts

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

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

现在您可以将“useValueAsDate”应用于日期输入控件。

演示

当然,有一个演示: http://johanneshoppe.github.io/angular-date-value-accessor/

答案 3 :(得分:3)

我开始尝试实施Ankit Singh的解决方案,并遇到了一些验证和时区问题。 (即使在尝试了该答案的评论部分中的建议之后)

相反,我选择使用moment.js来处理使用ISO8601格式日期字符串的字符串和日期之间的转换。我过去使用moment.js取得了很好的成绩,所以这不是一个困难的决定。似乎对我有用,希望其他人觉得这很有用。

对于我的Angular 2应用程序,我运行了npm install --save moment,然后将Ankit的解决方案转换为围绕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;
    }
}

然后是HTML:

<input type="date" name="someDate" [(ngModel)]="ngDateModel.dateInput"/>

答案 4 :(得分:2)

使用此代码修复它:

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>

答案 5 :(得分:2)

我认为已接受的答案缺少将输入日期字符串转换为Date对象的函数调用。所以这个:

(ngModelChange)="startDate = $event"

应该是这样的:

(ngModelChange)="startDate = toDate($event)"

我正在使用Moment.js,这使事情变得更加容易:

my.component.ts

...
import * as moment from 'moment';
...
@Component ({
  ...
})
export class MyComponent implements OnInit {

  public fromDate: moment.Moment;
  public toDate: moment.Moment;
  
  ngOnInit() {
    this.toDate = moment();
    this.fromDate = moment().subtract(1, 'week');
  }

  dateStringToMoment(dateString: string): moment.Moment {
    return moment(dateString);
  }

my-component.html

...
<input type="date" min="{{ fromDate | date:'yyyy-MM-dd' }}" name="toDate" [ngModel]="toDate | date:'yyyy-MM-dd'" (ngModelChange)="toDate = dateStringToMoment($event)">
<input type="date" max="{{ toDate | date:'yyyy-MM-dd' }}" name="fromDate" [ngModel]="fromDate | date:'yyyy-MM-dd'" (ngModelChange)="fromDate = dateStringToMoment($event)">
...

答案 6 :(得分:0)

创建了本地字符串变量

dateField: string;

然后将其绑定到表单上

日期输入

<input type="text" class="form-control" required [(ngModel)]="dateField" />

稍后只需在调用任何API之前将其分配回Date属性

insert() {
    this.myObjet.date = new Date(this.dateField);
    ... call api

update() {
    this.myObjet.date = new Date(this.dateField);
    ... call api