【问题标题】:Knockout two way custom binding to split ISO datetime in date and time fields淘汰两种自定义绑定以在日期和时间字段中拆分 ISO 日期时间
【发布时间】:2018-02-10 22:22:35
【问题描述】:

我在服务器端有一个日期时间字符串YYYY-MM-DDT03:00,在客户端有一个moment.js。

我需要将绑定处理程序的更新和初始化阶段都绑定到我的可观察日期时间属性,但无法让它与表单输入一起使用。

这是文本元素的工作思路(仅更新阶段):

ko.bindingHandlers.date = {
    update: function(element, valueAccessor) {
        var options = ko.unwrap(valueAccessor);
        var value = ko.unwrap(options.value);
        var text = moment(value).format('DD/MM/YYYY');
        ko.utils.setTextContent(element, text);
    },
};
ko.bindingHandlers.time = {
    update: function(element, valueAccessor) {
        var options = ko.unwrap(valueAccessor);
        var value = ko.unwrap(options.value);
        var text = moment(value).format('HH:mm');
        ko.utils.setTextContent(element, text);
    },
};

编辑 - 我尝试将我的问题与上下文联系起来。

实际上,作为一个淘汰赛和 js 新手 :),我正在尝试通过 ko.mapping 将来自服务器的以太 Json 数组(每个项目可以具有各种属性)映射到淘汰赛 observables。最终,我需要一个 ko 可观察数组,其中包含每个原始数组项的编辑/保存/取消/删除方法。

function EditableCollection(payload, updateUrl) {
    /* EditableCollections = { item: actual object,
     *                         data: actual data,
     *                         edit, editing Knockout facility,
     *                       }
     */
    var collection = this;
    collection.item = ko.mapping.fromJS(payload);

    collection.editing = ko.observable(false);

    collection.edit = function() {
        if (!self.condition()) {
            // UI logic
            collection._bkp = ko.mapping.toJS(collection.item);
            collection.editing(true);
        } else {
            // UI logic
        };
    };
    collection.cancel = function() {
        ko.mapping.fromJS(collection._bkp, collection.item);
        delete(collection._bkp);
        collection.editing(false);
        // UI logic
    };
    collection.item.cancel = collection.cancel;
    collection.save = function() {
        if (updateUrl) {
        $.ajax({
            url: updateUrl,
            method:'POST',
            dataType:'json',
            data: JSON.stringify($.extend(updateData, { 'item': ko.mapping.toJS(collection.item) })), // or something
            success: function(result){
            return result;
            },
            error: function(error){
            return error;
            },
        });
        };
        // UI logic
        delete(collection._bkp);
    };
    collection.item.save = collection.save;
};

最初的问题出现是因为当我面对包含 ISO 8601 字符串的项目的数组时,我需要在两个单独的属性日期和时间中进行转换。

所以我认为我不能使用 computedProperties。作为原始绑定方法的解决方法,我求助于在映射create function 中管理任务,但这对我来说效率非常低且丑陋:

var scadenzeMapping = {
create: function(options) {
    var payload = options.data;
    console.log(payload);
    // ** moment.js:
    // When refactoring for TIME will matter.
    var start = moment(payload.data_start); // e.g. 05/02/2018T00:00:00
    // TODO ** Verify timezone (external) handling...
    if (payload.isAllDay) {
        payload.sdate = start.format('DD/MM/YYYY');
        payload.stime = undefined;
        payload.edate = payload.sdate;
        payload.etime = undefined;
        payload.data_end = payload.data_start;
    } else {
        payload.sdate = start.format('DD/MM/YYYY');
        payload.stime = start.format('HH:mm');
        var end = moment(payload.data_end);
        payload.edate = end.format('DD/MM/YYYY');
        payload.etime = end.format('HH:mm');
    };
    // payload.data_start = start;
    return new EditableCollection(payload,
                                  '{{ put_event }}',
                                  );
    },
};

这是原始问题的主题上下文。

【问题讨论】:

  • ...我想我最终会在视图模型中保留 ISO 格式的日期时间和单独的日期和时间...
  • 几个computeds 会很好地为您服务。

标签: knockout.js


【解决方案1】:

首先,您的自定义绑定不订阅传递的 observable 的更改。如果你改变了

var options = ko.unwrap(valueAccessor);

var options = ko.unwrap(valueAccessor());

你的更新函数在传递的 observable 改变后被调用。


其次,如果您尝试在输入上使用此绑定,则无法使用

ko.utils.setTextContent(element, text);

因为它改变了元素的内容,而不是值。你需要使用

element.value = text;

我认为做这种事情的最好方法是不使用自定义绑定,使用可写计算,并使用标准值绑定,如下所示:

var myObservable = ko.observable();
var myComputed = ko.computed({
    write: function(val){
        myObservable(moment(val, 'DD/MM/YYYY').format('YYYY-MM-DDTHH:mm'))
    },
    read: function(){
        return moment(myObservable()).format('DD/MM/YYYY');
    }
})

在 html 中:

<input data-bind="value: myComputed"/>

【讨论】:

  • 毫无疑问,您和 Ray J 在建议使用 computedProperties 方面是正确的,但我的问题实际上与 ko.mapping 相关,正如我在上面的编辑中试图解释的那样。我认为重点必须是在 ko.bindingHandlers 中使用 init 函数。谢谢
  • @user2154587 您不需要在ko.mapping 中转换它们。您可以只存储未转换的日期,并在视图模型中有两个 computeds 将其转换为日期和时间。
猜你喜欢
  • 1970-01-01
  • 2015-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多