0

I'm currently using the Bing Maps KO custom binding to make using a Bing Maps control in Durandal nice and easy.

So far I've extended the custom binding to allow for an info box and that works fine as I simply have to set the value of an observable in the view model and the info box updates.

Now I would like to be able to call a function on one of the map objects contained within the custom binding.

I wish to have the map zoom to a specific point. Note that I don't want to set the maps centre point, but I wish to call the function that will handle the animating of the map to that point.

This could be achieved by having an observable field which I set in the view model, then the custom binding has it's update function called, it grabs the value, calls the method and then resets the observable back to being empty.

That feels rather hacky but should work, and it doesn't really step outside of the lines of separation you should maintain when using MVVM.

Is there another way to achieve this using function syntax so that it more correctly describes whats happening. (I'm requesting a series of actions to happen, rather than setting a value.)

  • It feels hacky because it doesn't convey what's going on behind the scenes. Javascript isn't exactly known for guiding you towards understandable code, but as a developer you can try and stay on that path. –  Oct 25 '13 at 14:46
  • 1
    Asking for an alternative for a hypothetical working solution feels a little far-fetched. Wouldn't it be better to implement the solution and then ask for improvements? – RainerAtSpirit Oct 25 '13 at 16:05
  • I didn't actually mention if this was implemented or not. As you say this is hypothetical. I'm not asking for someone to fix my code, I'm asking if there is a known approach within these design patterns that would more clearly describe the intent of the action. If you're saying "This isn't hacky in the context of Javascript and these libraries/frameworks, this is the reality of it." then that's a perfectly reasonable answer. Just because something works doesn't mean it's a good solution, and I'm asking if there's a better solution because I lack experience in this area. –  Oct 25 '13 at 16:14
  • Apparently you expect that some code might have a flaw, but you're not sharing it. Without seeing what you got it's hard to tell if it's really a flaw or just your anticipation. BTW: Making it work is the most important step, from that point on it's just improvements to make it faster, more maintable etc. So if it's working, go for it and come back when you hit a **specific** issue. – RainerAtSpirit Oct 25 '13 at 17:04
  • MVVM means that the model is the information expert which means your approach is valid – Anders Oct 25 '13 at 19:34
  • @Anders: If I was implementing this using MVVM with WPF/Silverlight then this approach would absolutely not be valid because it's not expressing the intent of performing an action and rather indicates the setting of a value. However this isn't WPF or SL and so I'm asking if this is *the* way to do it with the technologies I'm currently using. Saying it's correct for MVVM isn't right because it's more to do with the language and the way programmers use it. What might be correct for a design pattern in one language can be different in another. –  Oct 26 '13 at 09:14
  • @RainerAtSpirit: Implemented now and working. Now can you share a bit of your experience from working with this? I'm not really sure why you say I shouldn't worry about best practices, that would suggest I should stop using durandal, knockout, and co too because while they introduce patterns that allow you to work in ways that are more robust and maintainable you can make stuff "work" just fine without them? –  Oct 26 '13 at 09:17
  • @AndyJ. Implemented sounds good. Please share the code and highlight your concern with the chosen approach. re best practices: I'm sorry to hear that my comment to come up with a workable solution came across that way. Workable solution in my definition is within the constrains of a given technology stack. – RainerAtSpirit Oct 26 '13 at 12:17

1 Answers1

0

One way to achieve this is using events.

You can pass the custom binding an event name and have it subscribe to that event.

Since I'm using Durandal I would normally use the built-in event system, but jsFiddle only has KnockoutJS available so the following example uses a small PubSub library in it's place.

This is example code, rather than anything that will be put in to production.

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);
  • 1
    Instead of jsFiddle you might give https://github.com/dFiddle/dFiddle-2.0 a try if you want to share some Durandal specific code. – RainerAtSpirit Oct 26 '13 at 12:22
  • Thanks for the heads up about dFiddle, I'll certainly keep it in mind for the future! –  Oct 28 '13 at 09:26