【问题标题】:Remove knockout js bindings on cloned element删除克隆元素上的淘汰赛 js 绑定
【发布时间】:2013-02-25 23:01:28
【问题描述】:

我正在使用淘汰赛 js 模板绑定功能将项目集合呈现给一个元素:

<script type="text/javascript">
    ko.applyBindings(new function () {
        this.childItems = [{ Text: "Test", ImageUrl: "Images/Image.png" }];
    });
</script>

<script type="text/html" id="template">
    <div class="childItem" data-bind="attr: { title: Text }">
        <img data-bind="attr: { src: ImageUrl }" />
    </div>
</script> 

<div class="childSelector" data-bind="template: { name: 'template', foreach: childItems }">
</div>

单击时,子项被克隆并放置到另一个元素中:

$(".childSelector").on("click", ".childItem", function () {
    var clone = $(this).clone()[0];
    ko.cleanNode(clone);
    $(".targetNode").append(clone);
});

问题是当源数据发生变化,模板重新绑定到新数据时,抛出如下错误:

未捕获的错误:无法解析绑定。消息:参考错误: 文本未定义;绑定值:attr: { title: Text }

我发现另一个帖子建议使用ko.cleanNode(element) 删除淘汰赛的绑定,但这并没有解决我的问题。

有没有办法删除克隆元素上的敲除绑定以防止重新绑定时出现此错误?如果不是,我将通过从单击的元素中提取所需数据来“手动”克隆元素。

Here 是我正在做的一个简单示例

【问题讨论】:

    标签: javascript jquery knockout.js


    【解决方案1】:

    您可以通过遍历 DOM 并移除 data-bind 属性和淘汰赛 cmets 从元素中移除所有淘汰赛绑定。

    使用removeDataBindings(clone);,但首先使用ko.cleanNode(clone) 清理节点以清除所有事件处理程序。

    var commentNodesHaveTextProperty = document.createComment("test").text === "<!--test-->";
    var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*-->$/ : /^\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*$/;
    var endCommentRegex =   commentNodesHaveTextProperty ? /^<!--\s*\/ko\s*-->$/ : /^\s*\/ko\s*$/;
    
    function isStartComment(node) {
        return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);
    }
    
    function isEndComment(node) {
        return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(endCommentRegex);
    }
    
    function traverseNode(node, func) {
        func(node);
        node = node.firstChild;
        while (node) {
            traverseNode(node, func);
            node = node.nextSibling;
        }
    }
    
    function removeDataBindings(element) {
        var koComments = [];
    
        traverseNode(element, function (node) {
            if (isStartComment(node) || isEndComment(node)) {
                koComments.push(node);
                return;
            }
            //remove the 'data-bind' attributes
            if (node.nodeType === 1) { //ELEMENT_NODE
                node.removeAttribute('data-bind');
            }
        });
    
        //remove Knockout binding comments
        for (i = 0; i < koComments.length; i++) {
            node = koComments[i];
            if (node.parentNode) {
                node.parentNode.removeChild(node);
            }
        }
    }
    

    【讨论】:

    • 谢谢你,我接受了建议,并没有走我原来的路,但这回答了未来访客的问题!
    【解决方案2】:

    Oliver,像这样使用 jQuery 克隆绑定到淘汰赛的元素不是一个好主意。您应该对targetNode 使用数据绑定。如果您还没有这样做,最好通过Knockout Tutorials 了解基本用途。

    如果您尝试使用克隆按钮保留项目列表,这里是 dead simple fiddle,只使用 Knockout 来执行此操作。如果您想做其他事情,请告诉我;你的问题对你的目标并不完全清楚。

    HTML:

    <div data-bind="foreach: items">
        <span data-bind="text: $data"></span>
        <button data-bind="click: $parent.clone">Clone</button></br>
    </div>
    

    JS:

    var ViewModel = function(data) {
        var self  = this;
        self.items = ko.observableArray(data);
        self.clone = function(item) {
            //The ko.toJS here is a handy copy tool for viewModels
            //It isn't necessary for simple arrays like this one
            //But I included it because for an array of objects, you will want to use it
            self.items.push(ko.toJS(item));
        };
    };
    

    【讨论】:

    • 嗨 Tyrsius,以我的问题为例,在执行克隆后重新应用绑定时,控制台中会抛出错误。这是我第一次使用淘汰赛,但考虑一下,我可以将目标作为可观察数组,而不是克隆源项目......你知道是否有关于删除绑定问题的答案吗?
    • 我看到了错误,你看我的回答了吗?如果您使用 Knockout,则不应使用 jQuery 进行 DOM 克隆。该角色属于 Knockout。
    • 是的,清理克隆不是您代码中的问题。您实际上是在按钮功能中调用applyBindings。你不能这样做,因为原始(不是克隆)仍然有绑定。您应该永远两次致电applyBindings;更新绑定的 observables,节点将自行更新。您真的应该阅读这些教程。
    猜你喜欢
    • 2013-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多