如何在由挖空自定义绑定包装的对象上公开函数?

时间:2013-10-25 14:15:14

标签: knockout.js durandal custom-binding

我目前正在使用Bing Maps KO自定义绑定,以便在Durandal中轻松使用Bing Maps控件。

到目前为止,我已经扩展了自定义绑定以允许信息框,并且工作正常,因为我只需要在视图模型中设置observable的值并且信息框更新。

现在我希望能够在自定义绑定中包含的一个地图对象上调用一个函数。

我希望将地图缩放到特定点。请注意,我不想设置地图中心点,但我希望调用将处理地图动画的功能。

这可以通过在视图模型中设置一个可观察字段来实现,然后自定义绑定调用它的更新函数,它抓取值,调用方法然后将observable重置为空。

这感觉相当hacky但是应该可行,并且它并没有真正超出使用MVVM时应该保持的分离线。

是否有另一种方法可以使用函数语法实现此目的,以便更准确地描述发生的事情。 (我要求发生一系列行动,而不是设定价值。)

1 个答案:

答案 0 :(得分:0)

实现这一目标的一种方法是使用事件。

您可以传递自定义绑定事件名称并让它订阅该事件。

由于我正在使用Durandal,我通常会使用built-in event system,但jsFiddle只有KnockoutJS可用,因此以下示例在其中使用了一个小PubSub library

这是示例代码,而不是将要投入生产的任何内容。

jsFiddle

//PubSub//
(function(a,c,b){if(typeof module!=="undefined"){module.exports=b(a,c)}else{if(typeof define==="function"&&typeof define.amd==="object"){define(b)}else{c[a]=b(a,c)}}})("radio",this,function(b,c){function a(d){a.$.channel(d);return a.$}a.$={version:"0.2",channelName:"",channels:[],broadcast:function(){var f,j=this.channels[this.channelName],d=j.length,g,h,e;for(f=0;f<d;f++){g=j[f];if((typeof(g)==="object")&&(g.length)){h=g[0];e=g[1]||c}h.apply(e,arguments)}return this},channel:function(d){var e=this.channels;if(!e[d]){e[d]=[]}this.channelName=d;return this},subscribe:function(){var f=arguments,j=this.channels[this.channelName],g,e=f.length,h,d=[];for(g=0;g<e;g++){d=f[g];h=(typeof(d)==="function")?[d]:d;if((typeof(h)==="object")&&(h.length)){j.push(h)}}return this},unsubscribe:function(){var g=arguments,k,h,n=this.channels[this.channelName],f=g.length,e=n.length,m=0,d;for(k=0;k<f;k++){m=0;e=n.length;for(h=0;h<e;h++){d=h-m;if(n[d][0]===g[k]){n.splice(d,1);m++}}}return this}};return a});
//PubSub//

ko.bindingHandlers.customBinding = {
    _textBoxes: {},
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var _valueAccessor = valueAccessor();

        var textBox = document.createElement("input");
        textBox.type = "text";
        element.appendChild(textBox);

        ko.bindingHandlers.customBinding._textBoxes[element.id] = textBox;

        if(_valueAccessor.clearEventName) {
            radio(_valueAccessor.clearEventName).subscribe(function() {
                _valueAccessor.text("");
            });
        }

        if(_valueAccessor.text) {
            textBox.onchange=function() { _valueAccessor.text(textBox.value); };
        }
    },
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var _valueAccessor = valueAccessor();

        if(_valueAccessor.text) {
            ko.bindingHandlers.customBinding._textBoxes[element.id].value = _valueAccessor.text();
        }
    }
};

var viewModel = {
    text: ko.observable("Inital value."),
    doClear: function() {
        radio('clear').broadcast();
    },
    doReset: function() {
        viewModel.text("Reset value.");
    }
};

ko.applyBindings(viewModel);