适用Angular版本为:>=2。本文同样适用于Ionic这类的基于Angular实现的框架。
本文的思路也适用于控件显示的值和实际的值不一样时实现双向绑定。
1. 问题描述
在使用md2的datepicker控件时,遇到这样的问题,datepicker绑定的类型要求是Date
类型,但是传输后台需要的类型是基于YYYY-MM-DD
的日期字符串,但是Date
类型默认转换为字符串是这样的:Fri Jun 02 2017 16:03:50 GMT+0800 (China Standard Time)
,导致后台没有正确的处理日期。
这个问题可以从后台处理,提供对应格式的反序列化,但是不是最佳方案。日期类型基于不同的语言区域平台,其默认生成的格式也是不一样的。
那么如何在前端从根源上处理呢?
2. 思路分析
刚开始考虑了两种方案:
1、通过声明getter
、setter
方法,绑定对应的getter
、setter
属性,但是这样会造成绑定时脏检查的死循环问题,所以否定这种方案;
2、通过Pipe
,来实现将字符串转换为Date
类型,实现绑定,但是这只能解决单向绑定,对于双向绑定也无能为力。
最后,考虑能否结合以上两种方案呢?
好的,结果是成功的,我们下面就来介绍如何一步一步的解决这个问题。
3. 问题解决
3.1. 示例model
定义
这里定义一个People
的示例model
,只有一个属性birthday
,为string
类型。
import * as moment from 'moment';
export class People
{
birthday: string = "";
set ParseBirthday(val: Date){
this.birthday = moment(val).format("YYYY-MM-DD");
}
}
在这里我们生成了一个setter
方法,用来将Date
类型数据转换为对应格式的string
类型。
3.2. 定义string
类型单向绑定的pipe
代码如下:
import { Pipe, PipeTransform } from '@angular/core';
import * as moment from 'moment';
@Pipe({
name: 'stringToDate',
})
export class StringToDatePipe implements PipeTransform {
transform(value: string, format: string, ...args) {
if(!format) format = "YYYY-MM-DD";
if(!!value && moment(value, format).isValid()){
var dVal = moment(value, format);
return dVal.toDate();
}
return null;
}
}
这个Pipe
的目的就是将String
类型转换为Date
,这里可以传递一个format参数,为String
类型对应的日期格式。
3.3. 最后我们进行一种改造的双向绑定
<md2-datepicker [ngModel]="p.birthday | stringToDate:'YYYY-MM-DD'" (ngModelChange)="p.ParseBirthday=$event" type='date' format='y-M-d'></md2-datepicker>
上面我们将原本基于[(ngModel)]
的双向绑定,拆分成了一个单向绑定[ngModel]
和一个ngModelChange
事件处理,其中[ngModel]
的单向绑定,是通过3.2节中定义的Pipe
将String
类型的birthday
转换为Date
类型进行绑定;然后当数据改变时,通过(ngModelChange)
事件,通过setter
方法将Date
类型重新转换为String
,并赋值给birthday
。
OK,问题解决了,完工。
附录
本文中使用了Moment.js
来进行日期格式处理,可以通过如下命令安装相关依赖:
npm install moment --save