如何在Knockout.js中的模型和视图之间转换数据?

时间:2016-02-10 14:22:42

标签: javascript knockout.js data-binding

我接手了一个严重依赖于knockout.js数据绑定技术的项目。该应用程序的目的基本上是显示(运动)课程。必需的是课程名称和开始时的日期(和时间)。 数据通过ajax拉取,然后通过knockout.js绑定到视图

基本上,有一个模型看起来像这样:

BaseModel: function() {
    var self = this;

    var mappingOptions = {};
    self.setMappingOptions = function (options) {
        $.extend(mappingOptions, options);
    };
    self.map = function (data) {
        ko.mapping.fromJS(data, mappingOptions, self);
        return self;
    };

    self.isNew = function() {
        return !(typeof(self.id) == 'function' && self.id() != null);
    };
}

Course: function() {
    BaseModel.call(this);
    var self = this;

    ko.mapping.fromJS({
        name: null,
        date: moment().tz('UTC').minute(0).second(0).format('YYYY-MM-DDTHH:mm:ssZ'),
        timezone: null,
        duration: null
    }, {}, self);

    self.duration = ko.integerObservable();
    self.dateDateTime = new IMWeb.ko.DateTime(self.date);
    self.timezone = self.dateDateTime.timezone();
    self.dateDateTime.timezone.subscribe(function(timezone) {
        self.timezone = timezone;
    });
}

视图将此模型绑定为:

<input type="text" class="form-control" id="nameInput" data-bind="value: name"/>
<input type="text" class="form-control" id="dateInput" data-bind="value: clientDateDateTime.date, event:{focus: $parent.onDateInput, mouseover: $parent.onDateInput}, enable: changeable"/>
<input id="timeInput" type="text" class="form-control" data-bind="value: dateDateTime.time, event:{focus: $parent.onTimeInput, mouseover: $parent.onTimeInput}, enable: changeable">

从服务器发送的json数据中的日期设置为UTC,因此我创建了以下函数以将其转换为客户端的时区:

/**
 * Converts the given UTC date to local date of the client by subtracting
 * the local timezone offset from the given date.
 *
 * @param {Date} utcDate The date object to convert
 * @returns {Date} The converted date object
 */
var UTC2LocalDate = function (utcDate) {
    var timestamp = utcDate.getTime();              // Number of miliseconds since Jan 1st 1970, 0:00:00 UTC
    var offset = (new Date()).getTimezoneOffset();  // Local client offset in minutes
    timestamp -= offset * 60 * 1000;                // Fix date with offset by converting offset minutes to miliseconds
    return new Date(timestamp);
};

现在,这是一个棘手的部分:我如何运行这个&#34;转换代码&#34;没有干扰数据绑定机制?

基本上,我希望这种行为发生:

  • 模型更改 - &gt;模型中的日期将使用UTC2LocalDate()转换为客户的本地时区,并且视图会更新(更改模型的原始UTC值)。

  • 用户更改<input>中的值 - &gt;日期/时间转换为UTC并保存到模型。

2 个答案:

答案 0 :(得分:1)

来回转换最好由writable computed处理。您将拥有UTC日期的普通可观察量,以及基于它计算的可写值。基本结构如下:

vm.utcDate = ko.observable();
vm.localDate = ko.computed({
  deferEvaluation: true,
  read: function () {
    return toLocalDate(vm.utcDate());
  },
  write: function (newLocalDate) {
    vm.utcDate(toUtcDate(newLocalDate));
  }
});

(我显然已将toLocalDatetoUtcDate的实现留给您了。)在要显示的任何绑定中使用localDate变量和/或接受本地日期。它会在utcDate更新后自动更改,并会在输入新的utcDate值时自动更改localDate

答案 1 :(得分:0)

我的方法是在用于构造dateDateTime之前使用UTC2LocalDate转换self.date的值。此时,您的用户将与本地日期时间进行交互。

接下来,你可以编写一个转换回来的函数,让我们称之为Local2UtcDate,并通过订阅self.dateDateTime来更新你的self.date值。它看起来像这样:

self.duration = ko.integerObservable();
self.dateDateTime = new IMWeb.ko.DateTime(UTC2LocalDate(self.date));
self.timezone = self.dateDateTime.timezone();
self.dateDateTime.timezone.subscribe(function(timezone) {
    self.timezone = timezone;
});
self.dateDateTime.subscribe(function(changedLocalDate){
    self.date(Local2UtcDate(changedLocalDate));
});

我不确定服务器预计会回发什么,但这样self.dateDateTime将是本地时间,self.date将是更新的UTC时间。