Pages

Wednesday, October 1, 2014

Create a Responsive HTML Table using FooTable Plug-in and apply Client Side Binding using Handlebars.Js library

Idea

Our main idea is to eliminate server side grid controls and its associated view state using html table elements and improve the page performance. Also, we are going to add responsive behavior to our table to fit in all devices.

Summary

In this article, we are going to create responsive HTML Table using FooTable Plug-in and update the client side binding logic using Handlebars.js templating library. This is an extension to the project created using article Create an ASP.NET Web Forms Application using Bootstrap and Web API.

Process

A. Create HTML table and bind the data retrieved using Web API
B. Add responsive behavior to HTML table using FooTable plug-in
C. Update client side data binding logic with Handlebars.js library

A) Create HTML Table and Bind the Data Retrieved using Web API

First and foremost, we need to create a Model folder to the existing project where we can have our "Member" entity.

Go ahead and create a new Member.cs class with all required properties.

public class Member
{
   public int MemberId { get; set; }
   public string FirstName { get; set; }
   public string MiddleName { get; set; }
   public string LastName { get; set; }
   public string EmailId { get; set; }
   public string NickName { get; set; }
   public int Age { get; set; }
   public string IsActive { get; set; }
   public DateTime CreatedDate { get; set; }
   public string Company { get; set; }
}


Next, we are going to create a Repository.cs class to fetch predefined list of members.

Note: Replace the Model and Repository with your existing business logic entities and data access.

public class Repository
{
   public List GetMembers()
   {
      return new List {
         new Member {
MemberId = 1, FirstName = "Jeffrey", MiddleName = "Preston",
LastName = "Jorgensen", EmailId = "abc1@xyz.com",NickName = "Jeff Bezos", Age=50, IsActive = "Active", CreatedDate = new DateTime(2014,9,9), Company ="Amazon"
},
         new Member {
MemberId = 2, FirstName = "Satyanarayana", MiddleName = "",
LastName = "Nadella", EmailId = "abc2@xyz.com",NickName = "Satya Nadella", Age = 46,IsActive = "Active", CreatedDate = new DateTime(2014,9,9), Company="Microsoft"
},
         new Member {
MemberId = 3, FirstName = "Adele", MiddleName = "Laurie Blue",
LastName = "Adkins", EmailId = "abc3@xyz.com",NickName = "Adele",
Age = 26,IsActive = "Active", CreatedDate = new DateTime(2014,9,9), Company="Singer"
},
         new Member {
MemberId = 4, FirstName = "David" ,MiddleName = "Robert Joseph",
LastName = "Beckham", EmailId = "abc4@xyz.com",NickName = "Beckham",
Age = 39,IsActive = "Inactive", CreatedDate = new DateTime(2014,9,9), Company="Soccer Player"
}
      };

   }
}


Now, we need to create a Controller to access data related to member. Select an Empty Web API 2 Controller with the name MemberController.cs to our controller folder and add an action method GetMembers to list all members.

public class MemberController : ApiController
{
   Repository _repository = new Repository(); 

   [HttpGet]
   [ActionName("GetMembers")]
   public string GetMembers() 

   {
      List members = _repository.GetMembers();
      return JsonConvert.SerializeObject(members);
   }
}


Note: Get appropriate references to Model and Newtosoft Json within the Controller class.

Now, our solution looks like this:

Build and run the application to check if we can access member controller at the URL.

http://localhost:2469/api/Member/GetMembers


Alright, now we can see list of members in JSON format. Go ahead and create a new Content Page MemberList.aspx to the existing Master page to display the list of members in table format.


Note: We have three
elements in the content page. First
to hold the page header, second
to hold the actual table (gvMembers) with data and the last a hidden
(BodyStructure) to hold the row structure.

We have a table with thead section with all required column headers and tbody section with a warning message "No records found!". To view the page, set the new content page as start up page and run the application.


Next, we will add our JavaScript logic within the page ScriptSection to fetch data from our API.

Good Practice: Place all your logically related script within JavaScript Container not to leak JavaScript variables as global variables into the page. Container is similar to a C# class where we encapsulate members. This is what our Container looks like:


Note: As you can see from the success callback/promise method getMembersSuccess, we are looping through the data to clone the row structure and assign values to each column. And finally appending the new row to the table tbody section.

We are going to add our Service API link to the WebConfig appSettings so that it can be accessed from client side.

<appSettings>
   <add key="ApiPath" value="http://localhost:2469/api/"/>
</appSettings>


Also, add an IIFE (Immediately Invoked Function Expression) JavaScript statement to fetch data as soon as page loads.

$(function () {
   MembersList.getMembers();
})();


(or) you can also use jQuery ready method.

$(document).ready(function () {
   MembersList.getMembers();
});


Now, our ScriptSection looks like this:


Build and run the application to view the page:


As you can see, this is just a normal HTML table with no formatting and doesn’t fit well over various devices. Particularly, when looking in small devices like mobile and tablets.


B) Add Responsive Behavior to HTML Table using FooTable Plug-In

FooTable plug-in is a jQuery plugin that aims to make HTML tables on smaller devices look awesome - No matter how many columns of data you may have in them. As per the instructions, lets add required .css, .js and font files to our solution and it will look like this:


Now, we need to add style and script references to our content page. Footable Core Footable.core.css in the StyleSection, footable.js in the ScriptSection and wrap the table element with footable method in the ContentSection.


Build and run the updated code to check if the HTML table is responsive or not. Surprisingly, it isn't.


Why because, we have not taken advantage of the FooTable Break Points. Break Point is the predefined device width configured at FooTable to fix the table in mobile and tablet layouts. So we will add necessary data attributes to the table thead section.

<thead>
   <tr>
      <th data-toggle="true">Member Id</th>
      <th data-hide="phone" >First Name</th>
      <th data-hide="tablet,phone">Middle Name</th>
      <th data-hide="phone">Last Name</th>
      <th data-hide="tablet,phone">Email Id</th>
      <th>Nickname</th>
      <th data-hide="tablet,phone">Age</th>
      <th data-hide="tablet,phone">Status</th>
      <th data-hide="tablet,phone">Created On</th>
      <th>Company</th>
      <th data-hide="tablet,phone">Action</th>
   </tr>
</thead>


Note: Data-hide is used to hide columns off break-point limits. Data-toggle is used to show expand & collapse when in responsive mode.

Run the application again and check the table in Desktop, Tablet and Mobile layouts.

Tablet View

Mobile View

C) Update Client Side Data Binding Logic with Handlebars.js Library

Handlebars.js is a templating library effectively used to simplify data binding logic at client side. It is largely compatible with Mustache templates.

If you notice the success callback getMembersSuccess method, we are doing typical jQuery operations to fetch HTML table, parse the response and loop through the data to clone the dummy row and append it to the table body section.

This is absolutely fine doing this way. But there is an optimal way to bind the template using client side data binding technique with libraries such as Mistache, HandlebarsJs, Closures, UnderscoreJs, etc. In this article, we are focusing on Handlebarsjs.

To use Handlebarjs, we will create a new content page MemberListTemplate.aspx with the same content as we have in MembersList.aspx. As we are using handlebar template, go ahead and remove the div BodyStructure.

Next, we need to add Handlebarsjs JavaScript library to our project. You can either use NuGet Package Manager to search and download "Handlebars.js" or go to their website and download latest Version 2.0.0.


Add reference to the js file in ScriptSection just below the FooTable.js. Now, we will place our HTML template with in JavaScript which is of type "text/x-handlebars-template". We can also use "text/html" apart from any other JavaScript type here. The idea here is that the browser should not parse the template as regular JavaScript block.

<script id="template1" type="text/x-handlebars-template">
   {{#each members}}
   <tr>
      <td>{{MemberId}}</td>
      <td>{{FirstName}}</td>
      <td>{{MiddleName}}</td>
      <td>{{LastName}}</td>
      <td>{{EmailId}}</td>
      <td>{{NickName}}</td>
      <td>{{Age}}</td>
      <td>{{IsActive}}</td>
      <td>{{CreatedDate}}</td>
      <td>{{Company}}</td>
      <td></td>
   </tr>
   {{/each}}
</script>


Note: The template will loop through members using #each handler to fetch appropriate items for binding.

Now, we will update our getMembersSuccess callback with the code given below:

getMembersSuccess: function (response)
{
   var data = $.parseJSON(response);
   var table = $("#gvMembers");
   // Remove tbody within the table

   table.find("tbody").html("");
   // Get The Template HTML from the source

   var template = $("#template1").html();
   // Compile it

   var compiledCode = Handlebars.compile(template);
   // Then, process compiled code using data as an input

   var dynamicCode = compiledCode(data);
   // Assign the output to placeholder

   table.find("tbody").append(dynamicCode);
   $('#gvMembers').trigger('footable_redraw');
}


Warning: Compiling your handlebarsjs template is often a time consuming process and will affect performance if it huge and or nested within. There is a way to precompile your templates beforehand to save run time.

If you look at the code, we are accessing the template (#template) using jQuery selector. Then compile the HTML using Handlebar compile method (which will convert HTML in a JavaScript method). Later, we process the compiledCode with the data as parameter and append the same to the table tbody element.

To view the changes, make the new content page MemberListTemplate.aspx as start up, build and run the application.


There are several ways to make HTML table responsive. However, I feel FooTable has done wonders in this area. It has several other features to Sorting, Filtering, and apply Theme along with Pagination.

There are several features included in Handlebarsjs with which you can do more complex operations. You can extend its behavior using adding Escaping, Expressions, Helpers and custom handlers, etc.

Hope you had something new to learn from this article. Let me know if you have any suggestions or improvements.

Saturday, September 6, 2014

How To: Create an Asp.Net Web Forms Application with Bootstrap and Web API

Idea:
The idea of this article is to help you upgrade your existing project to satisfy current Html5 responsive design needs and to make it lightning fast by eliminating all server round trips. Basically we are trying to eliminate ViewState from the page to make it light weight on the client side. 

Summary:
In this article we are going to create an Asp.net web forms mobile first application using Bootstrap to design the layout, Web API as a service layer and jQuery for all asynchronous calls to the server. This way we could eliminate most of the code-behind logic and achieve tremendous performance boost.

Process:
A) Create a simple asp.net forms application using bootstrap template
B) Create bundle to optimize web resources
C) Add a service layer (Web API) with JSON format to the existing application

A) Create a simple asp.net forms application using bootstrap template
1. Start by creating a new Visual C# project in Asp.net and select an “Empty Web Application” from the New Project dialog. Click OK to create new project. (I used VS 2012)

  
Now your solution looks like this


2. Go ahead and create a Global.asax file to the project (We will update this later)
3. Right click on the project and select “Manage NuGet Package…” to install jQuery and then Bootstrap. This will create three new folders “Content” for CSS, “fonts” and “Scripts” to the project.

 
Note: I prefer to delete all .min.* and .map files from the newly created folders and use bundle technique to optimize web resources (will be discussed later)
Also, there is a new file “packages.config” created within the project where we can find all installed NuGet packages and their versions.


Warning: If there is a mismatch in package version between the installed and the one specified in packages.config file, Nuget gets confuses and will not work as expected
4. Now, we will create a master page (Main.Master) with three sections “StyleSection” in the header, “ContentSection” in the body and “ScriptSection” just before the closing body tag. For this sample we are going to use “Navbar” template from bootstrap templates. Get the source html from browser “View Page Source” and it in our master page at the bottom. Replace with downloaded html to replace and retain the master page behavior.
Note: Here we commented the form tag; If needed we can create form sections within our content page. Now, our Master page looks like this



5. Create a new content page “ContentPage.aspx”. Add the html code (div with class “jumbotron”) from the Bootstrap template into the “ContentSection”. Our code should look like this

6. Set the “ContentPage.aspx” as start page; build and run the application.
Laptop/Tablet View:


 Mobile View:



Note: If you see our Main.Master page, there are individual references to each of the .css and .js files. This will impact our page load time when there are numerous files added to the page. To fix this we need to create a bundle for Style and Script types.

B) Create Bundle to Optimize Web Resources
7. First we need to create a new folder “App_Start” to the root of the project.
8. Add a new class “BundleConfig.cs” to the folder with a static RegisterBundles method. Each script or style bundle is located at a virtual path as specified from the root (~/bundles/)



Note: The order in which the files added to the bundle is important; Check for any dependencies
9. To fix the BundleCollection missed reference; Install the package “Microsoft.AspNet.Web .Optimization” from NuGet



Note: Add “System.Web.Optimization;” namespace to the “BundleConfig.cs” file. Replace existing style and script tags with the bundle script pointing to the virtual path. Now, your master page should look like



10. Next we need to register our bundle within Application_Start of Global.asax file. Run the application to check if everything works fine. Now, if we view the page source it still shows individual link for each resource even after creating the bundle.



To see the bundle effect, we need to explicitly enable bundle optimization using the statement

 After enabling the bundle optimization, run the application to view the page source. All three script files combine into single and a minified version.


C) Add a service layer (Web API) with JSON format to the existing application


11. First we need to create a new folder "Controller" under project root directory. By default web forms don’t have Web Api. We need to rely on NuGet Package Manager to search for “Microsoft Asp.Net Web API 2.2” and install the package.


Note: This will also install “Newtonsoft.Json” library to serialize and de-serialize objects. If not, you can always find the package at NuGet.



12. Right click on the Controller folder and add new item. From the templates select Web API Controller Class and create "ProductController".


Note: You will see basic Get, Post, Put and Delete action methods. Comment all the code or extend it. I prefer to delete all actions and start new by adding new action method “GetHelloWorld” to test API
 


We need to set proper routing mechanism in order to access API methods. So let’s do that.
13. Add a new class "
WebApiConfig.cs" to the “App_Start” folder with code below


Note: Add reference to this namespace “System.Web.Http”. If your code throws an error at “config.EnableCors()”, go to NuGet and install Cors (Cross Origin Resource Sharing) package (Microsoft.AspNet.WebAPI.Cors) to access Web API from other domains.
 


14. Now, register our api router to the "Application_Start" method in Global.asax file using
WebApiConfig.Register(GlobalConfiguration.Configuration);
15. Now, try to access the API using the link http://localhost:7656/api/   



Note: We have not specifying the controller and action name in the above link. Those values are set to default values (as “ProductController” and “GetHelloWorld”) in the WebAPIConfig file. The result is seen in XML format which is the default Web API behavior.
16. To get the result in JSON (
JavaScript Object Notation) format; we need to set the media type headers to accept “text/html” using below statement in the WebAPIConfig Register method.

Now, run the api link again and this time you see result in JSON format



To learn more about XML and JSON serialization visit this link

Voila, hope you had a great learning experience. Let me know if you have any suggestions or improvements.