jQueryUI Resizable KnockoutJS Binding - CodeProject

:

: 4

Introduction

The solution here presented talks about how to bind jQuery interactions like Resizable, Draggable with the KnockoutJs MVVM. In this tip, I am going to demonstrate how to bind jQuery UI resizable to a Knockout Observable.

We are going to build a div and make it resizable so that the div can be resized. The width and the height of the expanded div would appear on the textboxes below as we resize the div.

Background

Basic Introduction about KnockoutJs:

KnockoutJS is a client side JavaScript library which implements the MVVM pattern. There is an excellent article written on MVVM pattern - http://www.codeproject.com/Articles/100175/Model-View-ViewModel-MVVM-Explained

KnockoutJS is built on three core features:

  1. Observables and Dependency Tracking
  2. Declarative Bindings
  3. Templating

Observables are special JavaScript that notify subscribers about changes and can automatically detect dependencies. Declarative Bindings are to link View Model to the View.

jQuery UI:

jQueryUI is a client side JavaScript library developed by the jQuery Team, which provides us with a collection of UI Widgets, visual effects, themes etc. Along with these, it provides us with the following interactions:

  1. Draggable
  2. Droppable
  3. Resizable
  4. Selectable
  5. Sortable

Let’s Begin

This sample is created using ASP.NET MVC application, and you can create this in any web application.

Open Visual Studio and create an ASP.NET MVC Empty Application. Create a Home Controller within the Controller Folder. Create a folder inside "View" folder named "Home". Right click, create a view "index.cshtml"

Open Package Manager Console, Run the following command to install the KnockoutJS library:

PM> Install-Package knockoutjs

This will bring the KnockoutJS library inside the Scripts Folder.

Open the Layout.cshtml remove all the references for the @scripts and place the following code:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>KnockoutJs Sandbox</title>
    <script src="~/Scripts/jquery-1.7.1.min.js"></script>
    <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
    <script src="~/Scripts/knockout-3.3.0.js"></script>
</head>
<body>
    @RenderBody()    
</body>
</html>

Let us create the HTML first. We will create a div, which would be made resizable and then two labels below that showing the width and the height respectively.

<div style="padding: 20px;">
    
    <div style="background-color:green">
    </div>
 
    <div>
        Height: <label></label>
        Width: <label></label>
    </div>
 
</div>

Then, we create the view model, containing two observables -> one to hold the width of the div and one to hold the height of the div. Since it needs to be bound to the div, we need to create two computed observables for returning the value in pixels.

<script>
    $(function () {
        var box = function (hght, wdth) {
            var self = this;
            self.ht = ko.observable(hght);
            self.wt = ko.observable(wdth);
            self.formattedht = ko.computed(function () {
                return self.ht() + "px";
            });
            self.formattedwt = ko.computed(function () {
                return self.wt() + "px";
            });
          }    
          ko.applyBindings(new box(50, 200));
        });
</script>

Now let us get back to the HTML and wire the observables to the DIV property. The Style Binding is applied and set the height and the width of the property has been set to the "formattedht" and "formattedwt" property respectively. The label text are bound to the same variable to see the value.

<div style="padding: 20px;">    
    <div class="box" style="background-color:green" 

	data-bind="style:{ height:formattedht, width: formattedwt }">
    </div>
    <div>
        Height: <label data-bind="text:formattedht" ></label>
        Width: <label data-bind="text:formattedwt" ></label>
    </div>
</div>

Now if we make the div resizable by calling the jQuery UI method, $(".box").resizable(); the value in the box will not change when the div is resized. Hence, we need to create a custom binding. Inside the script tag, insert the following code. Give a name to the custom binding name -> ko.bindingHandlers."resizable"

ko.bindingHandlers.resizable = {
          init: function (element, valueAccessor, allBindings, vModel, bindingContext) {
             $(element).resizable({
                  resize: function (event, ui) {
                      vModel.ht(ui.size.height);
                      vModel.wt(ui.size.width);
                  }
              });
          },
          update: function (element, valueAccessor, allBindings, vModel, bindingContext) {

          }
      };

In the "init" event, make the element resizable, attach the event handler "resize" get the height and width and set it to the viewModel "ht" and "wt" observable. That’s it. Now when you resize the div – box, the value of the width and the height gets displayed on the labels.