Tuesday, September 24, 2013

Knockout.js - Custom Bindings


Creating custom bindings is one of the best parts of Knockout. It's very, very easy, you just have to add an object to the ko.bindingHandlers object. The name of the property on this object will be the name of the binding. All binding handlers should have two functions: init and update. There are some cases when specifying only one of the functions is sufficient. Both functions get five parameters, of which the first two are the most important. The first is the element on which the binding is applied, and the second is the value accessor function which returns the bound value (sometimes it's a value, sometimes it's an observable). You will probably use these two all the time and the other three very rarely.
The init function is called when the bindings are applied and the update function is called every time when the referred observables are changed and also right after the init function.
Let's see an example:

 <html>  
      <head>  
           <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>  
           <script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script>  
           <script>  
                ko.bindingHandlers.slideUpDown = {  
                     init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {  
                          var visible = ko.utils.unwrapObservable(valueAccessor());  
                          if (visible) {  
                            $(element).show();  
                       } else {  
                            $(element).hide();  
                       }  
                  },  
                  update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {  
                       var visible = ko.utils.unwrapObservable(valueAccessor());  
                       if (visible) {  
                            $(element).slideDown();  
                       } else {  
                            $(element).slideUp();  
                       }  
                  }  
                };  
                $(document).ready(function() {  
                     ko.applyBindings({  
                          visible: ko.observable(false)  
                     });  
                });  
           </script>  
      </head>  
      <body>  
           <div>  
                <button data-bind="click: visible.bind($data, !visible())">Toggle</button>  
           </div>  
           <div style="width: 500px; height: 300px;">  
                <img style="width: 500px;" data-bind="slideUpDown: visible" src="http://knockoutjs.com/img/ko-logo.png" />  
                <img style="width: 500px;" data-bind="slideUpDown: !visible()" src="http://4.bp.blogspot.com/_Gkxrvtze9SA/S36o6zcsK6I/AAAAAAAAAvs/VmtcRcGhY_E/s320/Knockout+Punch.jpg" />  
           </div>  
      </body>  
 </html>  

In this example I created a binding called slideUpDown by which you can bind a Boolean value or an observable holding a Boolean value to the element. I bound two elements to the visible observable. In the second binding I bound the inverse of the returned value to the element for which I needed to make a function call, since visible is a function. (If I negated a function object, that would always be false.)
If you take a look at the update function inside the binding handler, you can see, that I call ko.utils.unwrapObservable with the value returned by the valueAccessor function. If an observable is passed to the unwrapObservable function, it fetches its value and returns it. If a simple - non-observable - value is passed as a parameter it simply returns it. (From Knockout v2.3.0 you can refer to this function as ko.unwrap as well. Read more about this version and the 3.0 beta in Steve Sanderson's blog.)
If the bound variable is changed to true, then jQuery's slideDown function will be called, otherwise slideUp.
The init function just hides or shows the element based on the bound value. It's necesarry, because in some browsers on some platforms the second image would slide up on page refresh.

Writing your own bindings is a great thing It eases your job quite a lot and your own collection of custom bindings will emerge after a while.
In the comments section, you could share with us the clever bindings you have written or you are planning to write.

No comments:

Post a Comment

Share It