自定义Knockout绑定无法正常工作

时间:2017-02-01 16:20:15

标签: javascript mvvm knockout.js

我创建了一个计算的observable,可以很好地格式化电话号码。当焦点偏离表单字段时,它将需要一串数字并将其删除为此格式xxx-xxx-xxxx。然后我有一个控制器动作剥离它格式化xxxxxxxxxx,然后它仍然存在于数据库中。然后我的计算的observable将其重新格式化为xxx-xxx-xxxx格式。

我现在想要创建一个可以在我们的应用程序中实现的可重用的自定义绑定处理程序。问题是我不能让它做最后一部分,它在表单字段中重新格式化它。所以,问题是当我点击更新时,表单字段显示数字为xxxxxxxxxx(与数据库中的数据相同)有没有人知道我需要通过自定义绑定工作来改变我的当前计算的可观察量? / p>

可观察

self.Phone = ko.observable(model.MainPhone ? model.MainPhone : "").extend({ maxLength: 20, minLength: 10 });

Computed Observable正常工作:

self.PhoneFormat = ko.computed(function () {
   var phoneFormatting = self.Phone()
       .replace(/\D+/g, "")
       .replace(/^[01]/, "")
       .replace(/(\d{3})(\d{3})(\d{4})/, "$1-$2-$3")
       .substring(0, 12);
   return self.Phone() ? self.Phone(phoneFormatting) : "";
}, self);

自定义绑定无法正常工作:

ko.bindingHandlers.formatPhone = {
    init: function (element, valueAccessor, allBindings) {
        var source = valueAccessor();
        var formatter = function () {
            return ko.computed({
                read: function() { return source(); },
                write: function(newValue) {
                    source(newValue.replace(/\D+/g, "")
                        .replace(/^[01]/, "")
                        .replace(/(\d{3})(\d{3})(\d{4})/, "$1-$2-$3")
                        .substring(0, 12));
                }
            });
        };

        ko.bindingHandlers.value.init(element, formatter, allBindings);
    },

    update: function(element, valueAccessor, allBindings) {
        var source = valueAccessor();
        var formatter = function() {
            return ko.computed({
                read: function() { return source(); },
                write: function(newValue) {
                    source(newValue.replace(/\D+/g, "")
                        .replace(/^[01]/, "")
                        .replace(/(\d{3})(\d{3})(\d{4})/, "$1-$2-$3")
                        .substring(0, 12));
                }
            });
        };

        ko.bindingHandlers.value.update(element, formatter, allBindings);
    }
};

2 个答案:

答案 0 :(得分:1)

感觉readwrite应该交换......

我想说你希望你的“源”数据只是数字。格式化数据主要用于显示目的。

我希望你的绑定中添加了computed图层,它可以做两件事:

  • 写入时,请先将格式化,然后再将其放入source
  • 阅读时,请添加正确的格式

我不确定我是否打破过你以前工作的东西,但它可能是这样的:

ko.bindingHandlers.formatPhone = {
  init: function (element, valueAccessor, allBindings) {
        var source = valueAccessor();
        var formatter = ko.computed({
          write: function(newValue) {
             source(newValue.split("-").join("")); 
          },
          read: function() {
            return source().replace(/\D+/g, "")
                   .replace(/^[01]/, "")
                   .replace(/(\d{3})(\d{3})(\d{4})/, "$1-$2-$3")
                   .substring(0, 12);
          }
        });

        ko.bindingHandlers.value.init(element, function() { return formatter; }, allBindings);
    }
};

var vm = { phoneNr: ko.observable("3456546512") };

ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
Via custom binding:
<input data-bind="formatPhone: phoneNr">
<br/>
Mimic external update:
<input data-bind="textInput: phoneNr">

答案 1 :(得分:0)

我不确定为什么会这样,但自定义绑定没有。 :(

<强> HTML:

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

KO Observable:

self.Phone = ko.observable(model.Phone ? model.Phone : "").trimmed();

KO Subscribable:

ko.subscribable.fn.trimmed = function () {
        return ko.computed({
            read: function () {
                return this().replace(/\D+/g, "")
                               .replace(/^[01]/, "")
                               .replace(/(\d{3})(\d{3})(\d{4})/, "$1-$2-$3")
                               .substring(0, 12);
            },
            write: function (value) {
                this(value.replace(/\D+/g, "")
                               .replace(/^[01]/, "")
                               .replace(/(\d{3})(\d{3})(\d{4})/, "$1-$2-$3")
                               .substring(0, 12));
                this.valueHasMutated();
            },
            owner: this
        }).extend({ notify: 'always' });
    };