清除Knockout.js上的节点后如何重新应用绑定?

时间:2016-06-23 15:30:05

标签: javascript jquery knockout.js

即使在Knockout上清除节点后,我也无法应用绑定。我正在尝试根据用户操作动态使用组件(单击按钮等)。

我创建了一个UIComponent类来处理组件,创建和删除它们:

    (function (window) {

      define(['knockout'], function (ko) {

        /**
         * Custom component to the given DOM node
         * @type {{render: UIComponent.render}}
         */
        var UIComponent = (function () {

            return {

                /**
                 *  Render a component
                 * @param {object} component
                 * @param {object} element
                 */
                render: function (component, element, childComponents) {

                    var tagName = element.tagName && element.tagName.toLowerCase();

                    if (ko.components.isRegistered(tagName)) {
                        ko.components.unregister(tagName);
                    }

                    if (undefined !== childComponents) {

                        childComponents.forEach(function (child) {

                            if (ko.components.isRegistered(child.tagName)) {
                                ko.components.unregister(child.tagName);
                            }

                            ko.components.register(child.tagName, child.component);
                        });
                    }

                    ko.components.register(tagName, component);
                    ko.applyBindings();
                },

                /**
                 * Removes a component
                 * @param {object} component
                 * @param {object} element
                 */
                remove: function (component, element) {

                    ko.components.unregister(component.name);
                    ko.cleanNode(element);

                    // Remove any child elements from node
                    while (element.firstChild) {
                        element.removeChild(element.firstChild);
                    }
                }
            };

        })();

        window.UIComponent = UIComponent;

        return UIComponent;
    });
})(window);

我正在使用RequireJS动态加载组件的文件,所以我声明了一个组件,其中包含一个包含viewModel javascript文件的对象和一个模板:

var QuoteForm = {
        viewModel: {
            require: '/scripts/components/sample-form.js'
        },
        template: {
            require: 'text!/templates/forms/available-products-quote-form.html'
        }
    };

我在UIComponent类上使用这个组件对象,如下所示:

UIComponent.render(QuoteForm, $('quote-form')[0]);

这是 sample-form.js 文件中的viewModel:

define(['knockout'], function (ko) {

    var SampleFormModel = function (params) {

    };

    SampleFormModel.prototype = {

        /**
         * Dispose any resources used on component
         */
        dispose: function () {
            console.log('SampleFormModel disposed');
        }
    };

    return SampleFormModel;
});

为了测试,我使用简单的setTimeout函数来模拟用户操作:

UIComponent.render(QuoteForm, $('quote-form')[0]);

setTimeout(function () {
  UIComponent.remove(QuoteForm, $('quote-form')[0]);
}, 2000);

setTimeout(function () {
  UIComponent.render(QuoteForm, $('quote-form')[0]);
}, 4000);

当第一个setTimeout执行时,我在控制台上记录了SampleFormModel disposed消息,但是当第二个setTimeout执行时,我从Knockout收到错误:

Uncaught Error: You cannot apply bindings multiple times to the same element.

即使Knockout处理组件,我也无法再次在同一节点上应用绑定。

3 个答案:

答案 0 :(得分:3)

就像Roy J所说,我正在将绑定应用于整个DOM。我只是对exports.handler = function (event, context) { try { console.log("event.session: " + event.session); 类进行了一些更改,只是为了将组件注册到特定元素:

UIComponent

现在它的工作就像一个魅力!

答案 1 :(得分:1)

您需要在对同一元素应用绑定之前清理元素,因此,您可以使用

清理元素
ko.cleanNode(element)

此函数将从要重新应用绑定的节点上删除所有绑定。

答案 2 :(得分:0)

我对Knockout Components还不是很熟悉,但我一直在看文档。

这里有一个小问题:

  

如果您希望组件的所有实例共享同一个viewmodel对象实例(通常不需要)...有必要指定viewModel:{instance:object},而不仅仅是viewModel:object。

http://knockoutjs.com/documentation/component-registration.html#registering-components-as-a-viewmodeltemplate-pair

查看代码,您实际上拥有HTML组件的多个实例(通过呈现两次),但您正在重用viewmodel。你试过这个:

var QuoteForm = {
    viewModel: {
        instance: { require: '/scripts/components/sample-form.js' }
    },
    template: {
        require: 'text!/templates/forms/available-products-quote-form.html'
    }
};