如何在ko.applyBindings()调用后应用组件绑定

时间:2014-09-08 18:55:23

标签: knockout.js amd knockout-components

有没有办法在ko.applyBindings()调用后应用组件绑定?

关键是,我使用requireJS来加载我的模块/组件异步。那么我如何知道所有绑定都已注册?

Demo JS Fiddle

ko.applyBindings();

ko.components.register('my-component',
    {
        viewModel: function() {
            this.name = ko.observable('My Name');
        },
        template: '<input type="text" data-bind="value: name"></input>'
    }
);

// Moving it here, it works:
// ko.applyBindings();

2 个答案:

答案 0 :(得分:5)

您可以使用几个部分来动态理解和加载组件。

1- A custom component loader

您可以创建一个组件加载器,它可以从组件名称中理解需要的文件。

为了举例,假设任何以my-开头的组件,我们希望按惯例从components目录中获取。

它可能看起来像:

//add a loader to the end of the list of loaders (one by default)
ko.components.loaders.push({
    getConfig: function(name, callback) {
        var widgetName;

        //see if this is one of our widgets
        if (name.indexOf("my-") > -1) {
            widgetName = name.substr(3).toLowerCase();

            //provide configuration for how to load the template/widget
            callback({
                require: "components/" + widgetName
            });
        } else {
            //tell KO that we don't know and it can move on to additional loaders
            callback(null);
        }
    },
    //use the default loaders functionality for loading
    loadComponent: ko.components.defaultLoader.loadComponent
});

如果默认加载程序找不到一个组件(尚未注册),那么这个组件就会启动。

2-我们仍然需要处理custom elements,因为这些也会在注册时失效。该文档描述了可以覆盖的ko.components.getComponentNameForNode方法,以便将元素标记动态转换为组件名称。

在我们的案例中,这可能看起来像:

var existingGetComponentNameForNode = ko.components.getComponentNameForNode;
ko.components.getComponentNameForNode = function(node) {
    var tagNameLower = node.tagName && node.tagName.toLowerCase();

    //if we found one of our tags, then use it as the component name
    if (tagNameLower.indexOf("my-") > -1) {
        return tagNameLower;
    }

    // call the original
    return existingGetComponentNameForNode.apply(this, arguments);
};

这是一个小提琴,它将这些与require.js放在一起:http://jsfiddle.net/rniemeyer/tgm8wn7n/

另外,请注意IE6-8警告here,因为它会影响动态了解自定义元素。

或者,您需要确保在该组件绑定到UI之前注册所有组件(不一定是在初始applyBindings时,但是一旦遇到需要绑定的组件)

答案 1 :(得分:0)

为了扩展RP Niemeyer的建议以确保在绑定被命中之前所有组件都已注册,我过去已成功完成此操作以加载我很少需要的组件。:

通过在根或控制器样式顶级模型的属性中使用组件并将其包装在with绑定中,可以确保在注册组件之前未尝试组件绑定。在分配属性之前,KO不会评估with内的任何内容。

这个例子比单词更容易解释!

所以这是你的代码,证明早期调用applyBindings,然后使用超时来模拟以后加载依赖于组件的代码:

标记:

<!-- ko with: Container -->
  <my-component>replaceme</my-component>
<!-- /ko -->

代码:

function Model()
{
        ko.components.register('my-component',
                {
                        viewModel: function() {
                                this.name = ko.observable('My Name');
                        },
                        template: '<input type="text" data-bind="value: name"></input>'
                }
        );
}

function RootModel()
{
        this.Container = ko.observable();

        this.load = function()
        {
                this.Container(new Model());
        };
}

var rootmodel = new RootModel();
ko.applyBindings(rootmodel);

setTimeout(function() { rootmodel.load(); }, 1000);

工作小提琴:http://jsfiddle.net/whelkaholism/dhaox1ae/