可以将自定义元素传递给params的对象,就像组件绑定一样吗?

时间:2014-09-05 19:26:53

标签: knockout.js

Knockout custom element是否可以将params属性绑定到像Component binding这样的对象?

例如,我定义了以下组件:

ko.components.register('user-widget', {
    template: '<p><span data-bind = "text:fullName" ></span></p>',
    viewModel: function (params) {
        this.fullName = params.firstName + ' ' + params.lastName;
    }
});

以下VM:

function VM() {
    this.user = {
        firstName: 'Joe',
        lastName: 'Baker'
    };
}

使用组件绑定时,我可以将VM的用户属性直接传递给params属性,如下所示:

<div data-bind='component:{name:"user-widget", params:user}'></div>

但是,当使用自定义元素时,我必须像这样取消用户属性:

<user-widget params="firstName:user.firstName, lastName:user.lastName"></user-widget>

我尝试使用带有组件绑定的自定义元素,如下所示:

<user-widget data-bind='component:{params:user}'></user-widget>

导致以下错误:

  

无法使用&#34;组件&#34;绑定到匹配a的自定义元素   成分

JsFiddle

2 个答案:

答案 0 :(得分:5)

您需要更改组件以接受用户参数,而不是每个单独的参数。

<user-widgetx params='user: user'></user-widgetx>
ko.components.register('user-widgetx', {
    template: '<p><span data-bind = "text:fullName" ></span></p>',
    viewModel: function (params) {
        this.fullName = params.user.firstName + ' ' + params.user.lastName;
    }
});

fiddle


我探索了调整绑定提供程序以挂钩解析代码的想法。我能够把事情搞定。但我必须警告你,这无论如何都是黑客攻击。这是使用Knockout v3.2测试,我不保证这将始终有效。至少,直到他们以其他方式添加以扩展淘汰赛的核心功能。

查看源代码,我注意到params解析代码正在使用knockout的内置绑定解析器。因此,如果我们可以以某种方式挂钩解析器,我们可以调整绑定字符串的解释方式以实现我们想要的。

这里的目标是创建一种新类型的绑定,以便将解析后的表达式视为实际绑定对象。这也可以在组件参数之外进一步使用。这样,我们可以在bindings / params中执行此操作:

<user-widget params='${user}'></user-widget>

现在${ }内的任何内容都可以被视为绑定/参数对象。

(function () {
    var originalParseBindingsString = ko.bindingProvider.prototype.parseBindingsString,
        re = /^\$\{(.+)\}$/;

    function extractBindableObject(objExpr, bindingContext, node, options) {
        var objBindingString = '_object: ' + objExpr,
            objGetter = originalParseBindingsString.call(this, objBindingString, bindingContext, node, options),
            obj = objGetter['_object']();
        return objectMap(obj, function (value) {
            return function () { return value; };
        });
    }

    function objectMap(obj, mapper) {
        if (!obj) return obj;
        var result = {};
        for (var prop in obj) {
            if (obj.hasOwnProperty(prop))
                result[prop] = mapper(obj[prop], prop, obj);
        }
        return result;
    }

    ko.bindingProvider.prototype.parseBindingsString = function (bindingsString, bindingContext, node, options) {
        var m = bindingsString.match(re);
        if (m) {
            return extractBindableObject.call(this, m[1], bindingContext, node, options);
        }
        return originalParseBindingsString.apply(this, arguments);
    };
}());

fiddle

答案 1 :(得分:0)

如果有人来这里寻找解决此问题的方法,我会这样解决:

注册组件时,使您的函数viewmodel构造函数仅用于接收包含所需所有参数的整个对象:

function gridViewModel(params) {
   var self = this;
   var gridConfig = params.gridConfig;
   self.data = gridConfig.data;
   self.currentPageIndex = ko.observable(0);
   self.pageSize = gridConfig.pageSize || 5;
   ...
}

ko.components.register("grid-widget", {
   template: { element: 'ko-grid'},
   viewModel: gridViewModel    
});

然后,您可以像这样使用自定义元素:

   <grid-widget params='gridConfig: gridConfig'></grid-widget>

第一个 gridConfig 是构造函数将在其上接收的参数
params.gridConfig ,第二个是您在最近的viewModel上下文中拥有的对象。