Click here to Skip to main content
Click here to Skip to main content
Articles » Web Development » ASP.NET » Howto » Downloads
 
Add your own
alternative version
Go to top

MVC Techniques with jQuery, JSON, Knockout, and C#

, 2 Jan 2012
Developing an Order Entry application with MVC.
CodeProjectMVC4.zip
ADODataService
ADODataService.csproj.user
bin
Debug
ADODataService.dll
Release
obj
Debug
TempPE
Release
Properties
NorthwindApplicationServices
bin
Debug
ADODataService.dll
NorthwindApplicationServices.dll
NorthwindBusinessServices.dll
NorthwindDataAccessServices.dll
NorthwindDataModel.dll
NorthwindViewModel.dll
Release
NorthwindApplicationServices.csproj.user
obj
Debug
TempPE
Release
Properties
NorthwindBusinessServices
bin
Debug
ADODataService.dll
NorthwindBusinessServices.dll
NorthwindDataAccessServices.dll
NorthwindDataModel.dll
NorthwindViewModel.dll
Release
NorthwindBusinessServices.csproj.user
obj
Debug
TempPE
Release
Properties
NorthwindDataAccessServices
bin
Debug
ADODataService.dll
NorthwindDataAccessServices.dll
NorthwindDataModel.dll
Release
NorthwindDataAccessServices.csproj.user
obj
Debug
TempPE
Release
Properties
NorthwindDataModel
bin
Debug
NorthwindDataModel.dll
Release
NorthwindDataModel.csproj.user
obj
Debug
TempPE
Release
Properties
NorthwindViewModel
bin
Debug
NorthwindDataModel.dll
NorthwindViewModel.dll
Release
NorthwindViewModel.csproj.user
obj
Debug
TempPE
Release
Properties
NorthwindWebApplication
App_Data
bin
ADODataService.dll
EntityFramework.dll
Microsoft.Web.Infrastructure.dll
Microsoft.Web.Optimization.dll
NorthwindApplicationServices.dll
NorthwindBusinessServices.dll
NorthwindDataAccessServices.dll
NorthwindDataModel.dll
NorthwindViewModel.dll
NorthwindWebApplication.dll
NorthwindWebControls.dll
System.Web.Helpers.dll
System.Web.Mvc.dll
System.Web.Providers.dll
System.Web.Razor.dll
System.Web.WebPages.Deployment.dll
System.Web.WebPages.dll
System.Web.WebPages.Razor.dll
Content
Images
DownArrow.gif
icon-calendar.gif
icon-delete.gif
icon-floppy.gif
icon-pencil-x.gif
icon-pencil.gif
Search3.gif
UpArrow.gif
themes
base
images
ui-bg_flat_0_aaaaaa_40x100.png
ui-bg_flat_75_ffffff_40x100.png
ui-bg_glass_55_fbf9ee_1x400.png
ui-bg_glass_65_ffffff_1x400.png
ui-bg_glass_75_dadada_1x400.png
ui-bg_glass_75_e6e6e6_1x400.png
ui-bg_glass_95_fef1ec_1x400.png
ui-bg_highlight-soft_75_cccccc_1x100.png
ui-icons_222222_256x240.png
ui-icons_2e83ff_256x240.png
ui-icons_454545_256x240.png
ui-icons_888888_256x240.png
ui-icons_cd0a0a_256x240.png
Controllers
Global.asax
Helpers
Images
accent.png
aspNetHome.png
bullet.png
facebook.png
findHosting.png
heroAccent.png
NuGetGallery.png
orderedListOne.png
orderedListThree.png
orderedListTwo.png
Search.gif
twitter.png
windowsLive.png
Models
NorthwindWebApplication.csproj.user
obj
Debug
TempPE
Properties
Scripts
Views
Account
Home
Orders
Products
Shared
NorthwindWebControls
bin
Debug
NorthwindWebControls.dll
Release
obj
Debug
TempPE
Properties
packages
AspNetMvc.4.0.10906.0
AspNetMvc.4.0.10906.0.nupkg
lib
net40
System.Web.Mvc.dll
AspNetWebPagesCore.2.0.10906.0
AspNetWebPagesCore.2.0.10906.0.nupkg
lib
net40
System.Web.Helpers.dll
System.Web.Razor.dll
System.Web.WebPages.Deployment.dll
System.Web.WebPages.dll
System.Web.WebPages.Razor.dll
EntityFramework.4.1.10331.0
EntityFramework.4.1.10331.0.nupkg
lib
net40
EntityFramework.dll
jQuery.1.6.2
Content
Scripts
jQuery.1.6.2.nupkg
jQuery.Ajax.Unobtrusive.1.0
Content
Scripts
jQuery.Ajax.Unobtrusive.1.0.nupkg
jQuery.UI.Combined.1.8.11
Content
Content
themes
base
images
ui-bg_flat_0_aaaaaa_40x100.png
ui-bg_flat_75_ffffff_40x100.png
ui-bg_glass_55_fbf9ee_1x400.png
ui-bg_glass_65_ffffff_1x400.png
ui-bg_glass_75_dadada_1x400.png
ui-bg_glass_75_e6e6e6_1x400.png
ui-bg_glass_95_fef1ec_1x400.png
ui-bg_highlight-soft_75_cccccc_1x100.png
ui-icons_222222_256x240.png
ui-icons_2e83ff_256x240.png
ui-icons_454545_256x240.png
ui-icons_888888_256x240.png
ui-icons_cd0a0a_256x240.png
Scripts
jQuery.UI.Combined.1.8.11.nupkg
jQuery.Validation.1.8
Content
Scripts
jQuery.Validation.1.8.nupkg
jQuery.Validation.Unobtrusive.1.0
Content
Scripts
jQuery.Validation.Unobtrusive.1.0.nupkg
knockoutjs.1.2.9.0
Content
Scripts
knockoutjs.1.2.9.0.nupkg
Microsoft.Web.Optimization.0.1
lib
net40
Microsoft.Web.Optimization.dll
Microsoft.Web.Optimization.0.1.nupkg
MicrosoftWebInfrastructure.1.0.0.0
lib
net40
Microsoft.Web.Infrastructure.dll
MicrosoftWebInfrastructure.1.0.0.0.nupkg
Modernizr.2.0.6
Content
Scripts
Modernizr.2.0.6.nupkg
System.Web.Providers.1.0.1
content
web.config.transform
EULA.rtf
lib
Net40
System.Web.Providers.dll
System.Web.Providers.1.0.1.nupkg
SQLScript
@using System.Collections;
@using System.Collections.Generic;

@model NorthwindViewModel.OrderViewModel
@{
    ViewBag.Title = "Order Entry Detail";
    
    ArrayList orderDetails = new ArrayList();

    foreach (var item in Model.OrderDetailsProducts)
    {                                            
        var orderDetail = new
	    {            
            ProductID = item.OrderDetails.ProductIDFormatted,
	        ProductName = item.Products.ProductName,
            Quantity = item.OrderDetails.Quantity,
            UnitPrice = item.OrderDetails.UnitPriceFormatted,
            QuantityPerUnit = item.Products.QuantityPerUnit,
            Discount = item.OrderDetails.DiscountFormatted            
        };

        orderDetails.Add(orderDetail);
    }

}

<h4>Order Entry Detail</h4>

<div style="float:left; width:150px; height:25px; text-align:right;" class="field-label" >Order Number:&nbsp;</div>
<div style="float:left; width:150px; height:25px; font-weight:bold; " >&nbsp;@Model.Order.OrderID</div>
<div style="float:left; width:150px; height:25px; text-align:right; " class="field-label">Customer ID:&nbsp;</div>
<div style="float:left; width:150px; height:25px; ">&nbsp;@Model.Customer.CustomerID</div>

<div style="clear:both;"></div>  

<div style="float:left; width:150px; text-align:right; height:25px;" class="field-label" >Order Date:&nbsp;</div>
<div style="float:left; width:150px; height:25px; ">&nbsp;@Model.Order.OrderDate.ToShortDateString()</div>                       
<div style="float:left; width:150px; height:25px; text-align:right;" class="field-label">Customer Name:&nbsp;</div>
<div style="float:left; height:25px; ">&nbsp;@Model.Customer.CompanyName</div>

<div style="clear:both;"></div>  

<!--====== Container ======-->
<table border="0" cellpadding="0"  cellspacing="0" style="width:100%">
<tr class="DataGridHeader">
<td style="width:10%; height:25px">Product ID</td>
<td style="width:30%">Product Description</td>
<td style="width:10%">Quantity</td>
<td style="width:10%">Unit Price</td>
<td style="width:15%">UOM</td>
<td style="width:10%">Discount</td>
<td style="width:15%">Edit Options</td>
</tr>
<tbody data-bind='template: {name: "OrderDetailTemplate", foreach: LineItems}'> </tbody> 
</table>


<div data-bind="visible: AddNewLineItem">
    <table style="width: 100%">
        <tr>
            <td style="width: 10%">
                <input id="ProductID" type="text" value="" onkeypress="ProductIDEntered(this,event);" style="width: 50px" />&nbsp;
                <img alt="Product Inquiry" title="Product Inquiry" style="vertical-align:middle" width="20px" height="20px"  onclick="ShowProductInquiryModal()" src="@Url.Content("~/Content/Images/search3.gif")" />
            </td>
            <td style="width: 30%">
                <span id="ProductName"></span>
            </td>
            <td style="width: 10%">
                <input id="Quantity" type="text" value=""  style="width: 50px" />
            </td>
            <td style="width: 10%">
                <span id="UnitPrice"></span>
            </td>
            <td style="width: 15%">
                <span id="QuantityPerUnit"></span>
            </td>
            <td style="width: 10%">
                <input id="Discount" type="text" value="" style="width: 50px" />
            </td>
            <td style="width: 15%">
                <img alt="save" title="Add item to order" onclick="AddNewLineItem()" src="@Url.Content("~/Content/Images/icon-floppy.gif")" />
            </td>
        </tr>
    </table>
</div>

<div style="padding: 20px 10px 10px 10px;">
<input id="btnAdd" type="button" onclick="ShowAddLineItem()" value="Add Line Item" />
<input id="btnOrderHeader" type="button" onclick="ShowOrderHeader()" value="Order Header" />

</div>

<div id="dialog-modal" title="Product Inquiry">
	<div id="ProductInquiryModalDiv">
    </div>
</div>

<div id="OrderDetailsData" style="visibility: hidden; display: none">
    @Html.Raw(Json.Encode(orderDetails));
</div>

@Html.Hidden("OrderID", Model.Order.OrderID)

<!--====== Template ======-->
<script type="text/html" id="OrderDetailTemplate">    

 <tr data-bind="style: { background: viewModel.SetBackgroundColor($data) }">
 
  <td style="height:25px"><div data-bind="text: ProductID"></div></td>
  <td><div data-bind="text: ProductName "></div></td>
  <td>
        <div data-bind="text: Quantity, visible: DisplayMode "></div>
        <div data-bind="visible: EditMode" >                   
            <input type="text" data-bind="value: Quantity" style="width: 50px"  />               
        </div>     
  </td>

  <td><div data-bind="text: UnitPrice"></div></td>
  <td><div data-bind="text: QuantityPerUnit "></div></td>
  <td>
        <div data-bind="text: Discount, visible: DisplayMode "></div>
        <div data-bind="visible: EditMode" >                   
            <input type="text" data-bind="value: Discount" style="width:50px" />               
        </div>     
  </td>
  <td>
        <div data-bind="visible: DisplayDeleteEditButtons">
            <div style="width:25px; float:left"><img alt="delete" data-bind="click: function() { viewModel.DeleteLineItem($data) }"   title="Delete item" src="@Url.Content("~/Content/Images/icon-delete.gif")" /></div>
            <div style="width:25px; float:left"><img alt="edit" data-bind="click: function() { viewModel.EditLineItem($data) }" title="Edit item" src="@Url.Content("~/Content/Images/icon-pencil.gif")" /></div>
        </div>
         <div data-bind="visible: DisplayCancelSaveButtons">
            <div style="width:25px; float:left"><img alt="save"  data-bind="click: function() { viewModel.UpdateLineItem($data) }" title="Save item" src="@Url.Content("~/Content/Images/icon-floppy.gif")" /></div>
            <div style="width:25px; float:left"><img alt="cancel edit" data-bind="click: function() { viewModel.CancelLineItem($data) }" title="Cancel Edit" src="@Url.Content("~/Content/Images/icon-pencil-x.gif")" /></div>
        </div>
  </td>
  </tr>

</script>

<div id="MessageBox" data-bind="html: MessageBox"></div> 

<div id="DeleteConfirmation" style="visibility:hidden">
<div id="dialog-confirm" title="Delete Confirmation?">
	<p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>
    <span id="DeleteConfirmationText"></span>
    </p>     
</div>
</div>


<form id="OrderEdit" method="post" action="/Orders/OrderEdit">
    <input id="OrderID" name="OrderID" type="hidden" /> 
</form>

<script language="javascript" type="text/javascript">

    initialLineItems = jsonParse($("#OrderDetailsData").text());
    $("#ProductInquiryModalDiv").html("");

    var lineItemDisplay = function () {

        this.ProductID;
        this.ProductName;
        this.Quantity;
        this.UnitPrice;
        this.QuantityPerUnit;
        this.Discount;
        this.OriginalQuantity;
        this.OriginalDiscount;
        this.EditMode;
        this.DisplayMode;
        this.DisplayDeleteEditButtons;
        this.DisplayCancelSaveButtons;
    };

    // Overall viewmodel for this screen, along with initial state
    var viewModel = {

        LineItems: ko.observableArray(),
        MessageBox: ko.observable(),
        AddNewLineItem: ko.observable(false),

        SetBackgroundColor: function (currentLineItemData) {
            var rowIndex = this.LineItems.indexOf(currentLineItemData);
            var colorCode = rowIndex % 2 == 0 ? "White" : "WhiteSmoke";
            return colorCode;
        },

        EditLineItem: function (currentLineItemData) {

            var currentLineItem = this.LineItems.indexOf(currentLineItemData);

            this.LineItems()[currentLineItem].DisplayMode(false);
            this.LineItems()[currentLineItem].EditMode(true);
            this.LineItems()[currentLineItem].DisplayDeleteEditButtons(false);
            this.LineItems()[currentLineItem].DisplayCancelSaveButtons(true);

        },

        DeleteLineItem: function (currentLineItemData) {

            var currentLineItem = this.LineItems.indexOf(currentLineItemData);

            var productName = this.LineItems()[currentLineItem].ProductName();
            var productID = this.LineItems()[currentLineItem].ProductID();

            ConfirmDeleteLineItem(productID, productName, currentLineItem);

        },

        DeleteLineItemConfirmed: function (currentLineItem) {
            var row = this.LineItems()[currentLineItem];
            this.LineItems.remove(row);
        },

        CancelLineItem: function (currentLineItemData) {

            currentLineItem = this.LineItems.indexOf(currentLineItemData);

            this.LineItems()[currentLineItem].DisplayMode(true);
            this.LineItems()[currentLineItem].EditMode(false);
            this.LineItems()[currentLineItem].DisplayDeleteEditButtons(true);
            this.LineItems()[currentLineItem].DisplayCancelSaveButtons(false);

            this.LineItems()[currentLineItem].Quantity(this.LineItems()[currentLineItem].OriginalQuantity());
            this.LineItems()[currentLineItem].Discount(this.LineItems()[currentLineItem].OriginalDiscount());

        },

        UpdateLineItem: function (currentLineItemData) {
            currentLineItem = this.LineItems.indexOf(currentLineItemData);
            var lineItem = this.LineItems()[currentLineItem];
            UpdateOrderDetail(lineItem, currentLineItem);
        },

        UpdateOrderDetailComplete: function (currentLineItem, discount) {

            this.LineItems()[currentLineItem].DisplayMode(true);
            this.LineItems()[currentLineItem].EditMode(false);
            this.LineItems()[currentLineItem].DisplayDeleteEditButtons(true);
            this.LineItems()[currentLineItem].DisplayCancelSaveButtons(false);

            this.LineItems()[currentLineItem].OriginalQuantity(this.LineItems()[currentLineItem].Quantity());
            this.LineItems()[currentLineItem].OriginalDiscount(discount);
            this.LineItems()[currentLineItem].Discount(discount);

        }

    }

    ko.applyBindings(viewModel);

    for (i = 0; i < initialLineItems.length; i++) {
        var newLineItem = CreateLineItem(initialLineItems[i]);
        viewModel.LineItems.push(newLineItem);
    }

    function CreateLineItem(LineItem) {

        var lineItem = new lineItemDisplay();

        lineItem.ProductID = ko.observable(LineItem.ProductID);
        lineItem.ProductName = ko.observable(LineItem.ProductName);
        lineItem.Quantity = ko.observable(LineItem.Quantity);
        lineItem.OriginalQuantity = ko.observable(LineItem.Quantity);
        lineItem.OriginalDiscount = ko.observable(LineItem.Discount);
        lineItem.UnitPrice = ko.observable(LineItem.UnitPrice);
        lineItem.QuantityPerUnit = ko.observable(LineItem.QuantityPerUnit);
        lineItem.Discount = ko.observable(LineItem.Discount);
        lineItem.BackgroundColor = ko.observable(LineItem.BackgroundColor);
        lineItem.EditMode = ko.observable(false);
        lineItem.DisplayMode = ko.observable(true);
        lineItem.DisplayDeleteEditButtons = ko.observable(true);
        lineItem.DisplayCancelSaveButtons = ko.observable(false);

        return lineItem;

    }

    function ShowProductInquiryModal() {
        var url = "/Products/BeginProductInquiry";

        $.post(url, null, function (html, textStatus) {
            ShowProductInquiryModalComplete(html);
        });
    }

    function ShowProductInquiryModalComplete(productInquiryHtml) {
        $("#ProductInquiryModalDiv").html(productInquiryHtml);
        $("#dialog-modal").dialog({
            height: 500,
            width: 900,
            modal: true
        });
        setTimeout("ProductInquiryInitializeGrid()", 1000);
    }

    function GetProductInformation(productID) {

        $("#dialog-modal").dialog('close');
        $("#ProductInquiryModalDiv").html("");

        var ProductLookup = function () {
            this.ProductID;
        };

        var productLookup = new ProductLookup();
        productLookup.ProductID = productID;

        var url = "/Products/GetProductInformation";

        $.post(url, productLookup, function (results, textStatus) {
            GetProductInformationComplete(results);
        });
    }

    function GetProductInformationComplete(results) {

        if (results.ReturnStatus == true) {
            $("#ProductID").val(results.ViewModel.Product.ProductIDFormatted);
            $("#ProductName").html(results.ViewModel.Product.ProductName);
            $("#QuantityPerUnit").html(results.ViewModel.Product.QuantityPerUnit);
            $("#UnitPrice").html(results.ViewModel.Product.UnitPriceFormatted);
            $("#Quantity").focus();
        }
        else {
            viewModel.MessageBox(results.MessageBoxView);
        }
    }

    function LineItem() {
        this.OrderID;
        this.ProductID;
        this.Quantity;
        this.Discount;
        this.RowIndex;
    };

    function ShowAddLineItem() {
        viewModel.AddNewLineItem(true);
    }

    function AddNewLineItem() {
        var newLineItem = new LineItem();
        newLineItem.OrderID = $("#OrderID").val();
        newLineItem.ProductID = $("#ProductID").val();
        newLineItem.Quantity = $("#Quantity").val();
        newLineItem.Discount = $("#Discount").val();

        var url = "/Orders/AddOrderDetailLineItem";

        $.post(url, newLineItem, function (results, textStatus) {
            AddNewLineItemComplete(results);
        });

    }

    function AddNewLineItemComplete(results) {
        if (results.ReturnStatus == true) {

            var lineItem = new lineItemDisplay();

            lineItem.ProductID = results.ViewModel.OrderLineItem.OrderDetails.ProductIDFormatted;
            lineItem.ProductName = results.ViewModel.OrderLineItem.Products.ProductName;
            lineItem.Quantity = results.ViewModel.OrderLineItem.OrderDetails.Quantity;
            lineItem.UnitPrice = results.ViewModel.OrderLineItem.OrderDetails.UnitPriceFormatted;
            lineItem.QuantityPerUnit = results.ViewModel.OrderLineItem.Products.QuantityPerUnit;
            lineItem.Discount = results.ViewModel.OrderLineItem.OrderDetails.DiscountFormatted;

            var newLineItem = CreateLineItem(lineItem);
            viewModel.LineItems.push(newLineItem);

            $("#ProductID").val("");
            $("#ProductName").html("");
            $("#Quantity").val("");
            $("#Discount").val("");
            $("#UnitPrice").html("");
            $("#QuantityPerUnit").html("");

        }

        viewModel.MessageBox(results.MessageBoxView);

    }

    function UpdateOrderDetail(currentLineItem, rowIndex) {

        var updateLineItem = new LineItem();

        updateLineItem.OrderID = $("#OrderID").val();
        updateLineItem.ProductID = currentLineItem.ProductID(),
        updateLineItem.Quantity = currentLineItem.Quantity();
        updateLineItem.Discount = currentLineItem.Discount();
        updateLineItem.RowIndex = rowIndex;

        var url = "/Orders/UpdateOrderDetailLineItem";

        $.post(url, updateLineItem, function (results, textStatus) {
            UpdateOrderDetailComplete(results);
        });

    }

    function UpdateOrderDetailComplete(results) {
        if (results.ReturnStatus == true) {
            discount = results.ViewModel.OrderLineItem.OrderDetails.DiscountFormatted;
            viewModel.UpdateOrderDetailComplete(results.RowIndex, discount);
        }

        viewModel.MessageBox(results.MessageBoxView);

    }


    function ConfirmDeleteLineItem(productID, productName, currentLineItem) {

        $("#DeleteConfirmationText").html("Are you sure you want to delete <b>" + productID + " - " + productName + "</b> from this order?");

        $("#dialog-confirm").dialog({
            resizable: false,
            height: 200,
            width: 600,
            modal: true,
            buttons: {
                "Delete line item": function () {
                    DeleteLineItem(productID, productName, currentLineItem);
                    $(this).dialog("close");
                },
                Cancel: function () {
                    $(this).dialog("close");
                }
            }
        });

    }

    function DeleteLineItem(productID, productName, currentLineItem) {

        var orderID = $("#OrderID").val();

        var postData = {
            OrderID: orderID,
            ProductID: productID,
            ProductName: productName,
            RowIndex: currentLineItem
        };

        var url = "/Orders/DeleteOrderDetailLineItem";

        $.post(url, postData, function (data, textStatus) {
            DeleteLineItemComplete(data, textStatus);
        });

    }

    function DeleteLineItemComplete(results) {

        viewModel.MessageBox(results.MessageBoxView);

        if (results.ReturnStatus == true) {
            viewModel.DeleteLineItemConfirmed(results.RowIndex);
        }

    }


    function ShowOrderHeader() {
        $("#OrderEdit #OrderID").val($("#OrderID").val());
        $("#OrderEdit").submit();
    }

    function ProductIDEntered(element, e) {

        var key;

        if (window.event)
            key = window.event.keyCode;     //IE
        else
            key = e.which;     //firefox

        if (key == 13) {
            viewModel.MessageBox("");
            event.keyCode = 0;
            var productID = $("#ProductID").val();
            GetProductInformation(productID) 
        }

    }

   

</script>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Mark J. Caplin
Software Developer Caplin Systems
United States United States
Mark Caplin has specialized in Information Technology solutions for 25 years. Specializing in full life-cycle development projects for both enterprise-wide systems and Internet/Intranet based solutions.
 
For the past ten years or so, Mark has specialized in the Microsoft .NET framework using both C# and VB.NET as his tools of choice.
 
When not coding, Mark enjoys playing tennis, listening to U2 music, watching Miami Dolphins football and watching movies in Blu-Ray technology.
 
In between all this, his wife of over 20 years, feeds him well with some great home cooked meals.
 
...

| Advertise | Privacy | Mobile
Web04 | 2.8.140926.1 | Last Updated 2 Jan 2012
Article Copyright 2011 by Mark J. Caplin
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid