MVVM with ASP.net Using knockout JS Library


Download Sample Code

If you are a WPF or Silverlight developer; you should be familiar with the fancy binding and notification Mechanisms in it.

MVVM pattern is dependent on these mechanisms to view data binding expressions.

Fortunately, Steven Sanderson created a brilliant library to use MVVM pattern with ASP.net and he called it Knockoutjs

What is Knockout library?

Knockout is a JavaScript library that helps you to create rich, responsive display and editor user interfaces with a clean underlying data model. Any time you have sections of UI that update dynamically (e.g., changing depending on the user’s actions or when an external data source changes), KO can help you implement it more simply and maintainably.

Knockout documentation

To learn this library you can start with this interactive tutorial http://learn.knockoutjs.com/

Now, Let’s do our first ASP.net application using this wonderful library

  • Create a new Empty Web Application. (Name it KOTest)
  • Create a new person class as follows
Public Class Person Private _FirstName As String Public Property FirstName() As String Get Return _FirstName
        End Get Set(ByVal value As String)
            _FirstName = value
        End Set End Property Private _LastName As String Public Property LastName() As String Get Return _LastName
        End Get Set(ByVal value As String)
            _LastName = value
        End Set End Property Private _Age As String Public Property Age() As String Get Return _Age
        End Get Set(ByVal value As String)
            _Age = value
        End Set End Property End Class 
  • Add a web Service (ASMX Service) and call it ViewModelService.asmx
  • After adding this service uncomment the first line
<System.Web.Script.Services.ScriptService()> _
  • And Paste this method to it.
    <WebMethod()> _
    Public Function GetPerson() As Person   Return New Person() With {
            .FirstName = "Mohammad",
            .LastName = "Najeeb",
            .Age = "27" }
    End Function
    • Add a new Web form page (call it ko.aspx).
    • Import two javascript libraries
      • jQuery 1.4.1 (You can download it from here)
      • knockout 1.2.1 (You can download it from here)
      • You can also add jQuery templates but I did not use it in my sample here (You can download it from here)
    <script src="JS/jquery-1.4.1.min.js" type="text/javascript"></script> <script src="JS/knockout-1.2.1.js" type="text/javascript"></script>
  • Now, Let’s create a person class in javascript
// Create a Person Class with Constructor  // that takes two parameters (First Name & Last Name) var person = function (fName, lName) {
    this.FirstName = ko.observable(fName),
    this.LastName = ko.observable(lName),
    this.Age = 0
};

As you see above. FirstName property and LastName property are Observables.

Observables (like FirstName and LastName) will notify the UI when they changed in viewModel object.

So the previous implementation for person class in javascript is similar to TwoWay binding in WPF.

If FirstName and LastName are not observables; The UI will display the values at the first time. but any change occurred in property will not be reflected to the UI.

Removing Observables from FirstName & LastName similar to OneTime binding mode in WPF.

Screen Shot 2011-07-30 at 8.59.59 PM
So if you want to do a OneTime binding change your person implementation in  JavaScript to be like this

var person = function (fName, lName) {
    this.FirstName = fName,
    this.LastName = lName,
    this.Age = 0
};

But viewModel is not binded to the UI till now!! And this is our next step.

  • Bind viewModel object to the UI & get the values from Server by calling the web service.
jQuery(function () {
    ko.applyBindings(viewModel);
    KOTest.ViewModelService.GetPerson(onSuccess,
                                      onFail,
                                      null, null);
});
  • As you know you need a Script manager to call the service. So please just add it at the top of the page inside the form tag.
  • When calling service succeeded; just set viewModel.person property
function onSuccess(result) {
            viewModel.person(new person(
                             result.FirstName,
                             result.LastName
                             ));
        }
  • Paste add this HTML in you page
<div<div> <label for="<%=txtFirstName.ClientID %>"> First Name</label> <asp:TextBox ID="txtFirstName" runat="server"  data-bind="value:person().FirstName"> </asp:TextBox> </div> <div> <label for="<%=txtLastName.ClientID %>"> Last Name</label> <asp:TextBox ID="txtLastName" runat="server"  data-bind="value:person().LastName"> </asp:TextBox> </div> <div> <asp:Button ID="btnSubmit" runat="server"  Text="Submit" /> </div> </div> 

This is all what I have for Now. And Another Happy Weekend had been finished Sad smile. Happy Ramadan for all. And See ya later.

Advertisements

Step by Step – Filtering List using Reactive Extensions (Rx Framework)


  1. Download Rx Framework from here.
  2. Install it.
  3. Create New Windows Forms project (you can choose WPF, Silverlight, WP7). I used WinForms in my example.
  4. Add TextBox and ListBox to it as you see below.

Screen shot 2011-07-14 at 1.50.46 AM

  5.   Add System.Reactive reference to your project (see image below).

Screen shot 2011-07-14 at 1.53.05 AM

6.  Create any dummy data (you can use any repository you want) and just to make things fast Smile

Screen shot 2011-07-14 at 1.51.58 AM

7. Add this chunk of code.

Screen shot 2011-07-14 at 1.52.17 AM

When TextChanged raised the subscribed code will be executed Asynchronously.

That’s it. As simple as that.

Good night. Smile

ASP.net Grid View with jQuery Ajax (Dynamic Load for ASCX HTML)


After a couple of months without touching anything related to WEB. I’m doing some refreshment by creating Web Diagram Tool using jQuery “Something like Visio on WEB”.

Also my brother asked me to help to him to do a paging using AJAX.

I found some articles that used Update Panel …Yuk!!! .. Come-on people! are you still use it!! Update Panel could be useful sometimes. But its not a full AJAX. It will create a request for the whole page and when response comes back; It will refresh the part which in update panel.

I did something deferent and better. Its not new at all. Actually I worked on this task before a couple of years; I’m doing some refreshment, my brother just triggered me when he ask.

Simply, I loaded the Usercontrol  dynamically. and the Usercontrol contains anything you want (in my case it’s a GridView). Tada! pretty easy.

to load controls dynamically use this static method. I you want to use it; just modify it by adding your control and set your own properties.

private static String GetGridControlContent(String controlLocation,
 int pgIndex, int pgSize)
 {
   var page = new Page();

   var userControl = (MyGridView)page.LoadControl(controlLocation);

   if (pgIndex < 0)
         pgIndex = 0;

   userControl.PageSize = pgSize;
   userControl.PageIndex = pgIndex;

   page.Controls.Add(userControl);

   String htmlContent = "";

   using (var textWriter = new StringWriter())
   {
    HttpContext.Current.Server.Execute(page, textWriter, false);
    htmlContent = textWriter.ToString();
   }
   return htmlContent;
 }

 

As you see above; you can pass any parameter to the Usercontrol by creating a properties in that user control. For me I created PageSize & PageIndex properties.

You can wrap this method in a web method to call it from Javascript.

[WebMethod]
public static string AjaxGetGridCtrl(int pgIndex, int pgSize)
{
     return GetGridControlContent("~/MyGridView.ascx", pgIndex, 
                                  pgSize);
}

 

So you can load you control using script mnager or using jQuery AJAX library. I used the 2nd choice

$.ajax({
    type: 'POST',
    url: 'MyDefault.aspx/AjaxGetGridCtrl',
    contentType: "application/json; charset=utf-8",
    dataType: 'json',
    success: function (data) {
       $('#mainDiv').html(data.d);
    },
    data: "{pgIndex:'" + pgIndex + "', pgSize:'" + pgSize + "'}"
 });

 

 

jQuery AJAX is really nice. Let’s talk more about the options above.

type: you choose you either GET, or POST options.

url: I request this URL using POST.

contentType: used when you want to send data to the server (data is the last option). is this case the data will be sent in JSON format with UTF-8 Encoding.

dataType: The type of data that you’re expecting back from the server.

success: response will be handled here; if request succeeded.

I n this example; the HTML result will be rendered in mainDiv element.

data: parameters will be sent to the web method here.

Current Page Index and Page Size are stored in a Hidden Fields. And when user clicked on Next button; the value will be added by 1. And the AJAX call started by sending the new PageIndex.

 

function FillGrid(flag) {

 var pgIndex = 0;
 var pgCurrentIndex = $('#txtPgIndex').attr('value');
 var pgSize = $('#txtPgSize').attr('value');

 switch (flag) {
      case 'prev':
          pgIndex = parseInt(pgCurrentIndex) - 1;
          break;
      case 'next':
          pgIndex = parseInt(pgCurrentIndex) + 1;
                    break;
            }

            $('#txtPgIndex').attr('value',pgIndex);

      $.ajax({
           type: 'POST',
           url: 'MyDefault.aspx/AjaxGetGridCtrl',
           contentType: "application/json; charset=utf-8",
           dataType: 'json',
           success: function (data) {
               $('#mainDiv').html(data.d);
           },
           data: "{pgIndex:'" + pgIndex + "', pgSize:'" + pgSize + "'}"
       });
    }

 

Calling GetGridControlContent will cause a crahs at this line

 
HttpContext.Current.Server.Execute(page, textWriter, false);
 
 
To avoid this crash; all you need to do is to add
a [run at server form tag] to your Usercontrol
 
 
<%@ Control Language="C#" AutoEventWireup="true" 
    CodeBehind="MyGridView.ascx.cs" 
    Inherits="test.MyGridView" %>
<form id="form1" runat="server">
<asp:GridView ID="gv" runat="server" AllowPaging="true" 
              AutoGenerateColumns="False">
    <Columns>
        <asp:BoundField DataField="ID" 
               HeaderText="First Name" Visible="false" />
        <asp:BoundField DataField="FirstName" 
               HeaderText="First Name" />
        <asp:BoundField DataField="LastName"
               HeaderText="Last Name" />
        <asp:BoundField DataField="Mobile" 
               HeaderText="Mobile" />
        <asp:BoundField DataField="EmpSalary" 
               HeaderText="Salary" />
        <asp:BoundField DataField="HiringDate" 
               HeaderText="Hiring Date" />
        <asp:BoundField DataField="DOB" 
               HeaderText="Date of Birth" />
    </Columns>
</asp:GridView>
<div id="pgingFooter">
    <a href="javascript:void(0);" id="prev">Previous</a> 
        &nbsp;|&nbsp; <a href="javascript:void(0);"
        id="next">Next</a>
</div>

</form>

 

And there is no magical things in the code behind for this user control, Just fill your GridView Control according to PageIndex & PageSize properties.

public partial class MyGridView : System.Web.UI.UserControl
    {
        private List<Employee> lstEmployees;

        public int PageSize { get; set; }
        public int PageIndex { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            lstEmployees = new List<Employee>();

            FillList();
            lstEmployees = 
                       lstEmployees.Skip(this.PageIndex * this.PageSize)
                                   .Take(this.PageSize).ToList();

            gv.DataSource = lstEmployees;
            gv.DataBind();
        }

        private void FillList()
        {
            for (int j = 1; j <= 100; j++)
            {
                lstEmployees.Add(new Employee { 
                     ID = j, FirstName = "First" + j, 
                     LastName = "Last" + j, 
                     Mobile = "+932 55 1212" + j, 
                     EmpSalary = j * 100, 
                     DOB = "12/12/1990", 
                     iringDate = "12/12/2010" });
            }
        }
    }

 

You can download the sample from here