敲除自定义处理程序以在禁用时隐藏文本框值

Knockout custom handler to hide textbox value if it is disabled

我有一个表单,基本上有一些在几个项目之间共享的属性。当您 select 文本框允许数据输入的项目的单选按钮时,一次只能 select 编辑一个项目。

我已经设置好一切并正常工作,但如果控件被禁用,我不希望绑定值显示在文本框中。我一直在尝试与处理程序一起工作,但我很难理解如何让事情按照我需要的方式工作。我看过 Ryan 的许多文章和他提供的自定义处理程序,但我需要顿悟,但在那之前我正在寻求你的帮助。另外,是否有更合适的方法来处理我创建的 IsEnabled 函数,或者这是最好的方法吗?

这是JSFiddle

已更新 JSFiddle,我没有执行值,而是尝试创建一个自定义处理程序来禁用和删除该值。它有点工作,但它在几次更新后停止并且值没有得到更新。

这是一些示例 HTML:

<ul>
    <li>
        <input type="radio" name="item" value="1" data-bind="checked:Selected" /> Item 1 <input type="text" data-bind="value:Price, enable:IsEnabled('1')" />
        </li>
    <li>
        <input type="radio" name="item" value="2" data-bind="checked:Selected" /> Item 2 <input type="text" data-bind="value:Price, enable:IsEnabled('2')" />
        </li>
    <li>
        <input type="radio" name="item" value="3" data-bind="checked:Selected" /> Item 3 <input type="text" data-bind="enabledValue:Price, enable:IsEnabled('3')" />
        </li>
    <li>
        <input type="radio" name="item" value="4" data-bind="checked:Selected" /> Item 4 <input type="text" data-bind="enabledValue:Price, enable:IsEnabled('4')" />
        </li>
</ul>

这是示例 JS:

var vm = {
    Selected: ko.observable('1'),
    Price: ko.observable(12), 
    IsEnabled: function(item){
        var selected = this.Selected();
        return (selected == item)
    }    
}

ko.applyBindings(vm);

(function (ko, handlers, unwrap, extend) {
    "use strict";
    extend(handlers, {
        enabledValue: {
            init: function (element, valueAccessor, allBindings) {
                var bindings = allBindings();
                var enabled = ko.unwrap(bindings.enable);
                var value = unwrap(valueAccessor());

                if (enabled)
                    handlers.value.init();
            },
            update: function (element, valueAccessor, allBindings) {
                var bindings = allBindings();
                var enabled = ko.unwrap(bindings.enable);
                var value = unwrap(valueAccessor());

                    handlers.value.update(element,function() {
                        if(enabled)
                            return valueAccessor(value);                       

                    });
            }
        }
    });
 }(ko, ko.bindingHandlers, ko.utils.unwrapObservable, ko.utils.extend));

托尼。我刚刚简化了您的示例,并让它在不同项目之间共享相同的值 属性。主要思想是绑定将存储内部 computed 并将针对它绑定一个元素。

extend(handlers, {
    enableValue: {
        init: function (element, valueAccessor, allBindings) {

            var showValue = ko.computed({
                read: function(){
                    if (unwrap(allBindings().enable)) {
                        return unwrap(valueAccessor());
                    } else {
                        return '';
                    }
                },
                write: valueAccessor()
            });

            ko.applyBindingsToNode(element, { value: showValue });

        }
    }
});

http://jsfiddle.net/7w566pt9/4/

请注意,在 KO 3.0 中,ko.applyBindingsToNode 已重命名为 ko.applyBindingAccessorsToNode

但是让绑定记住每个 item 的最后输入值不是更有意义吗?实现起来非常简单。

更新

记住特定项目的最后编辑值的方式与您应该在内部保留该值的方式类似 showValue。我们将其命名为 lastValue:

extend(handlers, {
    enableValue: {
        init: function (element, valueAccessor, allBindings) {

            // Create observable `lastValue` with some default content.
            // It will be created for EVERY binding separately.
            var lastValue = ko.observable(0);

            // If an item is currently enabled then set `lastValue` to the actual value.
            if (unwrap(allBindings().enable)) lastValue(unwrap(valueAccessor()));
            // This piece will be executed only once (for the selected item) and other
            // items will store default value in `lastValue`!

            // It's the internal anonymous computed intended to update bound
            // price to reflect currently edited value.
            ko.computed(function(){
                if (unwrap(allBindings().enable)) valueAccessor()(lastValue());
            });
            // Note that passed function will be triggered whenever item is enabled
            // and/or `lastValue` changes.

            // Here we just change valueAccessor() to `lastValue`.
            var showValue = ko.computed({
                read: function(){
                    if (unwrap(allBindings().enable)) {
                        return lastValue();
                    } else {
                        return '';
                    }
                },
                write: lastValue
            });

            ko.applyBindingsToNode(element, { value: showValue });

        }
    }
});

http://jsfiddle.net/7w566pt9/8/

我希望这几乎是您所期望的。通常在这种情况下,真正的问题不是实现功能而是描述功能应该如何工作。

由于我对答案的补充已被编辑掉,我添加了这个答案以帮助那些刚接触 KO 的人。

这是使用 ko.applyBindingAccessorsToNode 的 KO 3.0 实现。

extend(handlers, {
    enableValue: {
        init: function (element, valueAccessor, allBindings) {

            var showValue = ko.computed({
                read: function () {
                    if (unwrap(allBindings().enable)) {
                        return valueAccessor(); // CHANGED
                    } else {
                        return '';
                    }
                },
                write: valueAccessor //CHANGED
            });

            ko.applyBindingAccessorsToNode(element, { value: showValue }); //CHANGED

        }
    }
});

如发行说明中所述,目前还没有官方文档,但这是我能够整理的。我使用群消息来确定差异。希望这会节省一些人的时间,直到它有更多的文档。

Release Notes

ko.applyBindingsToNode is superseded by ko.applyBindingAccessorsToNode. The second parameter takes an object with pairs of bindings and value-accessors (functions that return the binding value). It can also take a function that returns such an object. (This interface isn't currently documented on the website.)

Group Message 来自 Michael Best 说它更好。

Compatibility Issue