Tuesday, June 11, 2013

How to Use Jquery Methods with Knockout

Knockout out provides a sophisticated way to use jQuery methods with your binding. You can use a custom binding feature provided by knockout for this purpose. Suppose I want to use SlideDown and slideUp methods of jQuery to show and hide the elements. Although it can be achieve by using the “visible” property of knockout, but I want to do it in a fancy way.

Add a sub property in ko.bindingHandlers and write your custom code in init and update method. This blog does not explain how to create custom binding. You can find its help in the knockout documentation. Here is the complete code of the custom binding for show/hide element using jQuery.
ko.bindingHandlers.collapseVisible = {
  
 init: function (element, valueAccessor) {

   var value = valueAccessor();
   $(element).toggle(ko.utils.unwrapObservable(value)); // Use "unwrapObservable" so we can handle values that may or may not be observable

 },
 
 update: function (element, valueAccessor, allBindingsAccessor) {

   var value = valueAccessor();
   var allBindings = allBindingsAccessor();

   // Grab some more data from another binding property
   var duration = allBindings.slideDuration || 500; 

   ko.utils.unwrapObservable(value) ? $(element).slideDown(duration) : $(element).slideUp(duration);

  }
 };



In the init method set the initial state of the element. This method calls once for each DOM element. Get element using $(element) and perform action which you want.

Whenever the associated observable change, the ko calls you update callback method. In this example I get the value of element using ko.utils.unwrapObservable(value) and call slideUp or slideDown method according to value.

Now next step is to bind your DOM element using ‘CollapseVisible’ custom binding.


 <div data-bind="collapseVisible: displayDetail, slideDuration: 1000" class="desc">
    Lorem Ipsum is simply dummy text of the ...
 </div> 


So whenever the value of displayDetail observable will change. The Update callback method will be called and according to value the slideUp and slideDown method will be called.

Complete Solution



Now here is complete working solution for it. Set style for your element.


 <script src="Scripts/jquery-2.0.0.js"></script>
 <script src="Scripts/knockout-2.2.1.js"></script>

 <style>
     .box
     {
       border: 1px black solid; width: 650px; margin-left: auto; margin-right: auto;
     }

     .box .title
     {
       padding: 8px; background-color: #e1e1e1; border-bottom: 1px black solid;
     }

     .box .title .showButton
     {
       float: right;
     }

     .box .desc
     {
       padding: 8px;font-size:12px;
     }
 
 </style>



Set your element, assign CSS classes and set binding etc.


 <div class="box">
    <div class="title">

       <span data-bind="html: title"></span>
       <a class="showButton" href="#" data-bind="html: showButtonText, event: { click: onShow }"></a>
    </div>
    <div data-bind="collapseVisible: displayDetail, slideDuration: 1000" class="desc">
         Lorem Ipsum is simply dummy...
    </div>
 </div>




Finally create your view model, custom binding and bind them to your page.


 <script type="text/javascript">

   var vm = {

      title: "Collapsible   Box",

      showButtonText: ko.observable('Show'),

      displayDetail: ko.observable(false),

      onShow: function () {

          var newVal = !this.displayDetail();


          this.displayDetail(newVal);
          this.showButtonText(newVal ? "Hide" : "Show");

      }

   };



   ko.bindingHandlers.collapseVisible = {
            
        init: function (element, valueAccessor) {

             var value = valueAccessor();
             $(element).toggle(ko.utils.unwrapObservable(value)); // Use "unwrapObservable" so we can handle 
                                                                  // values that may or may not be observable

            },            
        update: function (element, valueAccessor, allBindingsAccessor) {

                var value = valueAccessor();
                var allBindings = allBindingsAccessor();

                // Grab some more data from another binding property
                var duration = allBindings.slideDuration || 500; 

                ko.utils.unwrapObservable(value) ? $(element).slideDown(duration) : $(element).slideUp(duration);

            }
   };


   ko.applyBindings(vm);

 </script>