Knockout.js href Binding

I've been using this simple binding lately and I just thought I'd share. Sometimes I end up needing to construct URLs from viewmodel properties. Knockout has a built in binding that gets you there, attr.

With the built in binding, you have two options. First you can create a computed property on your viewmodel to do the concatenation and then bind the href attribute to that. The javascript looks something like this:

var viewmodel = {
    id:ko.observable('12345')
};
viewmodel.url = ko.computed(function(){
    return '/foo/'+this.id();
},viewmodel);

Then your binding will look like this:

<a data-bind="attr:{href:url}">Attr with computed</a>

It's not too bad on the binding side, but having to write that extra computed observable is tedious just to concatenate a couple of strings together. We can do better.

Your next option is to ditch the explicit computed observable and do the concatenation inside your binding. Knockout will create a computed on your behalf. That looks like this:

<a data-bind="attr:{href:'/foo/'+id()}">Attr with concat</a>

I like that we no longer need the extra computed, but that binding leaves a lot to be desired. There are a lot of things we can screw up in there. Let's fix this once and for all. First, let's look at the cleaned up binding.

<a data-bind="href:'/foo/:id'">Awesome</a>

That's more like it. Now, how do we make that happen?

ko.bindingHandlers.href = {
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var path = valueAccessor();
        var replaced = path.replace(/:([A-Za-z_]+)/g, function(_, token) {
            return ko.unwrap(viewModel[token]);
        });
        element.href = replaced;
    }
};

This binding takes advantage of overload of String.replace that allows you to pass a function to be evaluated when it comes time to resolve a replacement string. We then simply use that token and look up a property of the same name on our viewmodel to supply the replacement. Hopefully you will find it as useful as I have.

  • boubiyeah

    Simple and neat :)

  • http://kout.com/#/arkanciscan Jesse

    That’s a very useful binding. I love how simple and powerful customBindings can be. So much better than Angular directives!

  • Chandan Rajbhar

    Nice.