How to Use With Binding in Knockoutjs to Bind Multiple Controls in ASP.Net Application

Introduction

This article explains how to use With Binding in Knockoutjs to bind multiple controls in an ASP.NET Application.

In this article you will see that every control is related to some other control that may be considered as it's parent control and will be shown only when the parent control contains any useful data, otherwise other controls will not be shown and the user can't move forward.

Let's see the procedure required for creating such an application.

Step 1

For making such an application you need to add 3 js files to your application:

  1. Knockout-2.3.0.js
  2. jquerymin.js
  3. sampleProductCategories.js

You can download them from the internet (if you can find them) or can download the Zip file present at the top of this article and then can fetch the files from it.

    <script src="knockout-2.3.0.js"></script>

    <script src="jquerymin.js"></script>

    <script src="sampleProductCategories.js"></script>

SampleProductCategories.js contains a database of products that will be used in our application.

Step 2

Now we will work on the View Model of our application. Write this code in the View Model of your application.

        <script>

           

                function Currency(value) {

                    return "$" + value.toFixed(2);

                }

                var ProductRow = function () {

                    var self = this;

                    self.category = ko.observable();

                    self.product = ko.observable();

                    self.quantity = ko.observable(1);

                    self.total = ko.computed(function () {

                        return self.product() ? self.product().price * parseInt("0" + self.quantity(), 10) : 0;

                    });

                    self.category.subscribe(function () {

                        self.product(undefined);

                    });

                };

 

                var AllProduct = function () {

                    var self = this;

                    self.Row = ko.observableArray([new ProductRow()]);

                    self.FinalTotal = ko.computed(function () {

                        var complete = 0;

                        $.each(self.Row(), function () { complete += this.total() })

                        return complete;

                    });

                    self.addRow = function () { self.Row.push(new ProductRow()) };

                    self.removeRow = function (line) { self.Row.remove(line) };

                };

                ko.applyBindings(new AllProduct());

        </script>

Here first I created a function that will return the value of Products that will return the value of products with a $ sign.

After that I created a function named "ProductRow", in this function I took  three observables named "category", "product" and "quantity". By default the quantity is set to 1, but since these are made Observables, these can be changed at run time. I also created a Computed Function named "total", this computed function will return the Total Amount of each Row. One more function is created at the last that will change the type of products when the user changes the category.

Then I made a function named "AllProduct", in this function I made an Observable Array named "Row", this Row will be similar to the initial ProductRow. After that I created a computed Function named "FinalTotal," this computed function will return the grand total of all the selections made in each Row. After that I created two functions named "addRow" and "removeRow", these functions will be used to add a new Row or to delete an existing row of Product.

At the end the binding is applied to this "AllProduct".

Until now our work on View Model is completed so now we will move to the view of our application.

Step 3

Write this code in the view part of your application:

        <tbody data-bind='foreach: Row'>

            <tr>

                <td>

                    <select data-bind='options: sampleProductCategories, optionsText: "name", optionsCaption: "Select...", value: category'> </select>

                </td>

                <td data-bind="with: category">

                    <select data-bind='options: products, optionsText: "name", optionsCaption: "Select...", value: $parent.product'> </select>

                </td>

                <td class='price' data-bind='with: product'>

                    <span data-bind='text: Currency(price)'> </span>

                </td>

                <td class='quantity'>

                    <input data-bind='visible: product, value: quantity, valueUpdate: "afterkeydown"' />

                </td>

                <td class='price'>

                    <span data-bind='visible: product, text: Currency(total())' > </span>

                </td>

                <td>

                    <a href='#' data-bind='click: $parent.removeRow'>Remove</a>

                </td>

            </tr>

        </tbody>
  </table>
    <p class='FinalTotal'>
        Total value: <span data-bind='text: Currency(FinalTotal())'> </span>
    </p>
    <button data-bind='click: addRow'>Add product</button>

Here you can see that I had bound the Table body with the Array "Row" that will be bound by a foreach. After that I had bound the drop down list with the "category" Observable, other binding to the category I had passed the options to this Drop Down Menu through the "sampleProductCategories" and then provided the optionText: "name" that will retrieve the exact data given in the name category.

In the Next <td> you can see that I had bound it by using "with binding", and I had bound it with the category, in other words it will now become dependent on the category Observable and will work only when the category returns a value. In this <td> I had again made a drop down list bound with "product", it will search for the products in the database and then will search for the name of those Products.

The same is done in the next <td> except that instead of binding it with the category I had bound it with the Product, so it's dependent on the Product and will work according to the selection made in the Product Drop Down List. Then a Span is taken in this <td>, this Span will show the price of each row separately.

After that Binding is done for the quantity of the Products.

Next <td> contains the Span that will update the Price according to the number of quantity selected in each Row.

After that a Link Label is taken. When this Link Label is clicked "removeRow" is bound that will remove a Complete Row when user clicks on it.

Toward the end a Span and a button is taken. The Span is bound with the "FinalTotal" and Button is bound with the "addRow", Span will show the Grand total of all the Products and a button click will add a new row for selecting more Items to buy.

Output

Now you can run your application, on running the application you will get the output like this:

with binding1.jpg

You can see that until now only one Drop Down List is available and everything else is not visible. Now I will click on the Drop Down to select a Category.

with binding2.jpg

Now I will select a category and you will see that only that drop down Menu that is bound with the Category will become available to make a selection.

with binding3.jpg

Now I will select a Product from this Drop Down Menu and you will see that all those things that are bound to products will be available on the screen.

with binding4.jpg

Now as I change the Number of Items you can see that Total and Final Price is automatically updated.

with binding5.jpg