【问题标题】:Custom Knockout binding not working自定义淘汰赛绑定不起作用
【发布时间】:2017-06-13 13:49:37
【问题描述】:

我目前正在使用事件绑定来格式化电话号码(转换为 xxx-xxx-xxxx 格式),并且我想创建一个可重用的自定义绑定以供将来在我们的应用程序中使用。当前的事件绑定工作正常,但我无法让自定义绑定正常工作。任何人都可以看看下面并告诉我我的问题吗?

当前事件与 viewModel 方法的绑定:

<input class="form-control" id="Phone"  type="text" 
       data-bind="event: {blur: formatPhone}, enable: isInputMode, value: Phone" />

self.Phone = ko.observable(model.MainPhone).extend({ maxLength: 20 });

self.formatMainPhone = function() {
        var tempString = self.Phone().replace(/\D+/g, "").replace(/^[01]/, "").replace(/(\d{3})(\d{3})(\d{4})/, "$1-$2-$3").substring(0, 12);
        self.Phone(tempString);
    }

自定义绑定处理程序不起作用:

<input class="form-control max225" id="Phone" type="text" 
           data-bind="formatPhoneNumber: Phone, enable: isInputMode, value: Phone" />

self.Phone = ko.observable(model.MainPhone).extend({ maxLength: 20 });

ko.bindingHandlers.formatPhoneNumber = {
        update: function (element, valueAccessor) {            
            var phone = ko.utils.unwrapObservable(valueAccessor());
            var formatPhone = function () {
                return phone.replace(/\D+/g, "").replace(/^[01]/, "").replace(/(\d{3})(\d{3})(\d{4})/, "$1-$2-$3").substring(0, 11);
            }
            ko.bindingHandlers.value.update(element, formatPhone);
        }
    };

【问题讨论】:

    标签: javascript mvvm knockout.js


    【解决方案1】:

    您的绑定正试图劫持默认“值”绑定的更新,从淘汰源代码来看,该绑定似乎已被弃用。

    'update': function() {} // Keep for backwards compatibility with code that may have wrapped value binding

    您必须更改您的绑定,以便它使用 init。

    ko.bindingHandlers.value.init(element, formatPhone, allBindings);
    

    编辑:

    这可能更接近您想要的。这不是使用更新绑定,而是创建一个中间计算的 observable,然后使用 value.init 将文本框绑定到它。我们永远不需要更新绑定,因为计算将负责为您传播更改。

    ko.bindingHandlers.formatPhoneNumber = {
        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);
        }
      };
    

    编辑 2 - 更多解释

    使用 formatPhoneNumber 的更新绑定告诉 knockout 在值更改时运行该代码。这在理论上听起来不错,但让我们分解一下。

    1. 解开访问器并获取平面值。
    2. 创建一个返回格式化值的格式化函数。
    3. 搭载使用格式函数的值绑定。

    因为这是一个更新绑定,在步骤 1 中解开访问器会创建一个触发器,以便在访问器值更改时重新评估绑定。然后在第 3 步中,您将告诉敲除重新执行 value.update 绑定,该绑定当前只是一个空函数并且什么都不做。如果您将其更改为使用 value.init ,则实际上可能会用于格式化输出,但您是在告诉敲除在每次值更改时重新初始化 init 绑定。

    update: function(element, valueAccessor, allBindings) {
        var phone = ko.utils.unwrapObservable(valueAccessor());
        var formatPhone = function() { return phone.replace(...)}
        ko.bindingHandlers.value.init(element, formatPhone, allBindings);
    }
    

    绑定正在重新创建并传递新的初始值。这也意味着它只是一种单向绑定,因为对前端的更改无法使其返回到您的模型以更新支持的 observable。

    现在,如果您将自己的绑定更改为 init 绑定,并从那里调用 value.init 绑定,它只会被初始化一次,但下一个问题是您要绑定的函数不是不知道什么时候更新。

    init: function(element, valueAccessor, allBindings) {
        var phone = ko.utils.unwrapObservable(valueAccessor());
        var formatPhone = function() { return phone.replace(...)}
        ko.bindingHandlers.value.init(element, formatPhone, allBindings);
    }
    

    因为它只是一个普通的 js 函数,它被传递一个已经展开的平面值,它总是会根据 phone 的原始值给出相同的结果。将 value.init 绑定传递给计算后的 observable 可确保对访问器 observable 的更新触发格式化函数从现有绑定中更新。

    【讨论】:

    • 我刚刚添加到原始帖子中的建议更改是您所说的吗?
    • 不完全。我是说将现有的更新绑定更改为初始化绑定,但这仍然不能完全满足您的要求。见编辑。
    • 谢谢!我星期一回到办公室时会试试这个。我非常感谢您的帮助...
    • 成功了,杰森!太感谢了。你不知道我为此绞尽脑汁多长时间,我什至让它在这个小提琴jsfiddle.net/dfmmalaw/0619fj93 上工作,这就是为什么它没有在应用程序中工作没有任何意义。不过我还有一个问题。为什么使用计算出的 observable 有效,而不是更新绑定?我真的很想更好地理解这个概念。再次感谢。
    猜你喜欢
    • 2016-10-25
    • 1970-01-01
    • 2014-01-10
    • 2015-12-27
    • 1970-01-01
    • 1970-01-01
    • 2013-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多