Saturday, March 10, 2012

Knockout.js jQuery UI Dialog Binding

jQuery UI dialogs are a very useful way of displaying detail data but if you have a few of them nested in your view then Knockout JS data-binding requires some planning. The ko.applyBindings function can take a html element object as a second parameter and then it applies the binding to every element with a data-bind attribute in that scope. jQuery UI dialogs are div elements that may be nested within other elements that display the higher level data items. Consider the following example;

<div id="OrdersDiv">
   <input id="OrderIdText" type="text" data-bind="value: OrderId"/>

   <input id="CustomerNameText" type="text" data-bind="value: CustomerName"/>
   <a id="DialogLink" href="#" >Click here to see order details</a>
   <div id="OrderDetailsDialog">
      <input id="ProductNameText" type="text" data-bind="value: ProductName"/>
   </div>
</div>
<script type="text/javascript">
   var OrderViewModel = function () {
      var OrderId = ko.observable();
      var CustomerName = ko.observable();
   }
   
   $(document).ready(function () {
      $("#OrderDetailsDialog").dialog();
      var order = new OrderViewModel ();
      ko.applyBindings (order, document.getElementById ("OrdersDiv"));
   }
</script>

This code won't work since the OrdersViewModel doesn't have a ProductName property. One way to handle this problem is to create a view model object that contains the order details data as well. But this may result in unnecessary data transfer. We can create a custom binding to prevent KO from binding to child elements and then bind the child elements to the details view model as below;

<div id="OrdersDiv">
   <input id="OrderIdText" type="text" data-bind="value: OrderId"/>

   <input id="CustomerNameText" type="text" data-bind="value: CustomerName"/>
   <a id="DialogLink" href="#" >Click here to see order details</a>
   <div id="DetailsDiv" data-bind="stopBindings: true">
      <div id="OrderDetailsDialog">
         <input id="ProductNameText" type="text" data-bind="value: ProductName"/>
      </div>
   </div>
</div>
<script type="text/javascript">
   var OrderViewModel = function () {
      var OrderId = ko.observable();
      var CustomerName = ko.observable();
   }
   var OrderDetailsViewModel = function () {
      var OrderId = ko.observable();
      var ProductName = ko.observable();      

   }
   $(document).ready(function () {
      $("#OrderDetailsDialog").dialog();
      ko.bindingHandlers.stopBindings = {
          init: function () {
              return { 'controlsDescendantBindings': true };
          }
      };

      var order = new OrderViewModel ();
      var orderDetail = new OrderDetailsViewModel();
      ko.applyBindings (order, document.getElementById ("OrdersDiv"));
      ko.applyBindings (orderDetail, document.getElementById ("OrderDetailsDialog"));

   }
</script>

Reference: Knockout ignore binding, for nested viewModels?

No comments:

Post a Comment