Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

jQuery Templates/View Engines in ASP.NET MVC

0.00/5 (No votes)
26 Apr 2012 1  
This article explains how client-side view engines can be used in ASP.NET MVC.
This article introduces a different concept of the view engine - a client-side view engine that renders a view in a client browser. In this concept, the model and the controller are still on the server-side. However, instead of the HTML, JSON is generated as an output from the server-side, it is accepted on the client-side, and HTML is generated using the JavaScript templating engine.

Table of Contents

  1. Introduction
  2. Background
  3. Using the Code
    1. Model
    2. Controller
    3. View
  4. Implementation
    1. List Page
    2. Details Page
    3. Edit Page
    4. Hierarchical View
  5. Conclusion
  6. History

Introduction

Microsoft ASP.NET MVC framework follows a standard MVC pattern - the Model contains data that will be shown, the Controller performs actions when some event happens, initializes the Model, and passes it to the View, and the View takes a Model and renders the HTML output that would be sent to the client browser. This architecture is shown in the following figure:

JavaScript-View-Engine/template-mvc.png

The client (browser) sends an HTTP web request to the server-side. On the server, we have controllers that handle the request, takes data using the model, and passes it to the view. The view generates HTML that should be sent back to client. In MVC 3, there are several view engines that can be used - the standard ASP.NET view engine, Razor, Spark, NHaml, etc. All of these view engines use different syntax for generating the view; however, they all work the same way - the model is taken on the server-side, formatted using the template, and HTML is sent to the client browser.

This article introduces a different concept of the view engine - a client-side view engine that renders a view in a client browser. In this concept, the model and the controller are still on the server-side. However, instead of the HTML, JSON is generated as an output from the server-side, it is accepted on the client-side, and HTML is generated using the JavaScript templating engine. This architecture is shown in the following figure:

JavaScript-View-Engine/template-json.png

Sending an HTTP request to the controller and handling the model is the same as in the standard method. However, instead of passing the model object directly to the server-side view, in this case, the model is sent to the client side formatted as a JSON object where it is processed by the client side view engine.

Background

This example shows how the client-side JavaScript template engine in the ASP.NET MVC project can be used instead of the standard server-side templating engines. JavaScript templating engines use JSON objects as a model and generate HTML on the client side. The principle of the JavaScript template engine is shown in the following figure:

JavaScript-View-Engine/templating-engine.png

With JavaScript template engines, you will need to pass the model object (usually some JavaScript object) to the view. The view will have a template that defines how this model object will be rendered. Once it binds the JavaScript model with the template, it will produce HTML as a standard server-side view engine. As you can see, client-side templating engines work the same way as standard server-side MVC rendering engines. The only difference is that the views are processed in the browser.

Currently, there are several templating engines such as jsRender (successor of the deprecated jQuery template), Knockout, Pure, noTemplate, jsTemplate, Populate, and jTemplates, but this example uses the jQuery loadJSON templating engine. The jQuery loadJSON plug-in is a templating engine that binds a JSON object to a clean HTML template and generates the view on the client-side. To bind the JavaScript model with a template, you will need to call something like the following line of code:

$("#template").loadJSON(model); //If you use loadJSON plugin
$("#template").render(model);   //if you use jsRender plugin

This call will take the HTML fragment from the HTML in the current browser, and use it as a template for binding with the JavaScript object (model). As an example, imagine that you have the following JSON object that should be placed in the template:

model = {
        "Name":"Emkay Entertainments",
        "Address":["Nobel House","London","UK"],
        "Contact":"Phone"
}
<div id="template">
     <textarea id="Name" />
     <span class="Address"></span>
     <input name="Contact" />
</div>

If you call loadJSON with this model applied to the template, you will get the following output:

<div id="template">
     <textarea id="Name">Emkay Entertainments</textarea>
     <span class="Address">Nobel House</span>
     <span class="Address">London</span>
     <span class="Address">UK</span>
     <input name="Contact" value="Phone"/>
</div>

This is a simple JavaScript templating engine that has all the necessary features to implement an effective client-side templating engine, however you have other ones too. As an example, the same code generated using the jsrender template would be:

var model = {
    "Name":"Emkay Entertainments",
    "Address":[{"Item":"Nobel House"},
               {"Item":"London"},
	       {"Item":"UK"}	       ],
    "Contact":"Phone"
}
<script id="template" type="text/x-jsrender">
 <textarea id="Name">{{:Name}}</textarea>
 {{for Address}}
	<span>{{:Item}}</span>
 {{/for}}
 <input name="Contact" value="{{:Contact}}"/>
</script>

In the JavaScript, you can see a very similar data structure. In the template are added placeholders that match the names of the properties surrounded with {{: and }}. Also, here you have the ability to use for loops. In order to load a model to the template, you will need to use something like the following code:

$( "#view" ).html(
  $( "#template" ).render( model )
);

As a result, an element with ID "view" will be populated with the HTML that is a result of the merging model and the template. The result will be like the one shown in the following example:

<div id="view">
     <textarea id="Name">Emkay Entertainments</textarea>
     <span>Nobel House</span>
     <span>London</span>
     <span>UK</span>
     <input name="Contact" value="Phone"/>
</div>

Although the loadJSON plug-in will be used in the examples, alternative implementation examples with Pure and jQuery template are shortly described in some sections.

Why are we using this architecture? There are a few benefits that come with this kind of architecture:

  1. Performances - In this architecture, view processing is moved to the browser, where are used resources of the browser. The server should return responses faster because there is no view processing on the server-side.
  2. Throughput - In this architecture, instead of the HTML being returned, a JSON object is returned which is smaller than HTML because it does not contain unnecessary tags that wrap pure information. JSON objects contain only data that should be shown and they are loaded faster.
  3. Caching - HTML templates that are used on the client side do not contain any data. Therefore, they can be cached and reused for different view pages. The only thing that changes is a JSON data that is loaded in the template.
  4. Cross platform support - In this architecture, the same web server can support different platforms, from mobile devices to standard browsers, without knowing who is the client. The server returns the same JSON data to all clients, and you can put different templates on the client side that will be the best match for the device resolution and supported features. As an example, on a mobile device, you can define a smaller template where will not be shown rich UI elements, while in a standard browser, you will use a full rich-client UI.

In the following sections, I will show you how to create a JSON based ASP.NET MVC application using client-site templating engines.

Using the Code

In this article, a code example is presented which demonstrates how a client-side view engine can be used in ASP.NET MVC. The following sections show how the jQuery loadJSON plug-in can be integrated into an ASP.NET MVC application in order to replace the standard server-side view engines.

Model

Two classes that contain information about companies and their employees are used as a model in this example. The source code of the Company/Employee model classes is given in the following listing:

public class Company
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public string Town { get; set; }
    public string Description { get; set; }
    public DateTime Date { get; set; }
    public string Contact { get; set; }
    public bool IsFeatured { get; set; }
    public string[] Country { get; set; }
    public string Logo { get; set; }
    public Employee Manager { get; set; }
    public Employee[] Employees { get; set; }
}
public class Employee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

The Company class has two references to the Employee class, one to the single employee representing the manager and the array of employees for this company.

These model classes will be serialized in the controller and the JSON representation of the instances of the Company/Employee classes will be provided to the view that is placed on the client-side.

Controller

The controller is not a standard controller that reacts on user action and returns the view as it works in standard server-side view engines. In the JavaScript templating engines, the controller should return just a JSON object that will be used as the model on the client-side. This JSON object will be accepted in the JavaScript templating function and the HTML output will be generated directly in the browser page. This example contains three pages: list of companies, details about a company, and a form where company details can be edited. Hence, there are two action methods that should be implemented in the controller. The first action returns a list of companies, and the second one returns a single company by ID (this action will be called when details are shown and when a form with company data is populated). The source code for the controller is given in the following listing:

public class CompanyController : Controller
{
    public ActionResult List()
    {
       return Json(DataRepository.GetCompanies(), 
                   JsonRequestBehavior.AllowGet);
    }

    public ActionResult Data(int? ID)
    {
       return Json(DataRepository.GetCompanies().First(
          c => c.ID == ID), JsonRequestBehavior.AllowGet);
    }
}

The Action methods take the model classes, format them as JSON results, and return the JSON to the view engine. The view engine on the client-side will call these actions when the model is required by the view.

View

When a JavaScript templating engine is used, the view can be a static page. You can use standard .aspx pages as views but a plain HTML page can be used as well. The given example has four view pages:

  1. The list page where the list of companies is shown
  2. The details page where a single company's details are shown
  3. An edit page where information about a single company is loaded into a form where the details can be changed and posted to the server-side (although posting the results is out of the scope of this article).
  4. A hierarchy page where how the client-side template can be used to render complex nested structures is shown - this is the only example where the Employee class will be used.

These are typical cases of usage of the client pages. In the following sections, these view pages are described in detail and how the client-side engines can be used to render them is explained.

Implementation

In this section, I will show how you can implement standard list, details, and edit pages with jQuery templates.

List Page

The list page is used to define a template that will be used to list the companies in the browser. A static view page is used in this example as shown in the following listing:

<html>
<head>
    <title>Listing JSON aray using the HTML template</title>
    <link rel="stylesheet" type="text/css" href="/Content/style.css" />
    <script src="/scripts/jQuery-1.4.4.min.js")" type="text/javascript"></script>
    <script src="/scripts/jQuery.loadJSON.js")" type="text/javascript"></script>
    <script language="javascript" type="text/javascript">
        $(document).ready(function () {
            $('li').loadJSON('/Company/List');
        });
    </script>
</head>
<body>
    <div id="page-wrap">
        <div id="contact-area">
            <ul>
                <li><a href="details.html" class="ID">
                <span class="Name"></span>
            </a><span class="Address"></span>
          </li>
            </ul>
        </div>
    </div>
</body>
</html>

There is a plain HTML code placed in the unordered list that defines the item template that will be used to generate output. This part of the code is shown in the following listing:

<li>    
    <a href="details.html" class="ID">
    <span class="Name"></span>
    </a>
    <span class="Address"></span>
</li> 

The li tag contains HTML elements whose class attributes match the properties in the model class. The view is initialized using this JavaScript line from the heading:

$('li').loadJSON('/Company/List');   

This line loads a JSON array from the /Company/List URL and loads it into the lI element. The Company/List URL activates the List method in the Company controller which returns a list of companies formatted as a JSON array. When the loadJSON plug-in gets applied on this element, properties of the objects are placed in the template. Moreover, this template item is replicated for each instance of the model in the array that is bound to the template. As a result, a set of li elements will be created representing the list of companies that are loaded from the /Company/List URL. Shown below is the generated view in the browser:

JavaScript-View-Engine/loadJSON-list.png

The jQuery loadJSON plug-in checks the type of HTML elements before it loads values in them. In most elements, the value will be placed as an inner text of the element (e.g., SPAN, P, or DIV tags). However, if it finds a link element, instead of inner text, the plug-in adds a property as an additional parameter in the URL placed in the href attribute. In the example above, the parameters ID=17, ID=18, ID=19, etc., are appended to the href attribute of the link. Therefore, to add a text of the link, you will need to place an additional SPAN tag inside the link that will be loaded from the different property. You can find a live example of the list functionality here.

Alternative Implementation using the jQuery Template/jsRender Template

Note that you can use any other template engine if you want. As an example, if a jQuery template is used, the template would be something like the code shown in the following listing:

<ul id="template">
    <li> 
        <a href="/Home/PopulateEdit/${ID}">${Name}</a>
        ${Address}
    </li>
</ul> 

In jQuery template, placeholders are names of properties enclosed in ${ and } - in the example above, the ID, Name, and Address properties of the JSON objects will be placed in the ${ID}, ${Name}, and ${Address} placeholders. The JavaScript code that should be used to load JSON data in the template is shown below:

//Prepare template based on the inner HTML in the UL tag with id "template"
$.template("my_template", $("#template").html());
//Perform AJAX call and pass returned JSON array to template
$.getJSON('/Home/Populate', function (data) {
    $("#template").html($.tmpl("my_template", data));
}); 

In the jQuery template, you need to take the template code placed in the unordered list with an id "template", and compile it using a $.template() method. The compiled template can be referenced by the name my_template when the view is generated. Then, an AJAX call is executed to load JSON from the /Populate/List URL and data returned by this controller is bound to the template and set as the HTML code of the unordered list with an id "template". The result of the template is the same as the result returned by the loadJSON plug-in - there is only a different syntax for the view and initialization code.

The jQuery template plug-in is now deprecated, no longer in active development or maintenance. I would recommend to use jsRender instead. It has very similar sintax with minor changes. As an example, in the jsRender, instead of the ${ID} you are using:

  • {{:ID}} if you want to put raw value of data, or
  • {{>ID}} if you want to use HTML encoding

Equivalent code that loads HTML from the template using the data returned via AJAX is shown in the following example:

//Perform AJAX call and pass returned JSON array to template
$.getJSON('/Home/Populate', function (data) {
    $("#view").html($("template").render(data));
});

As you can see, it is very similar, so if you are already using jQuery template plugin and you want to convert your code to other template, I would recommend jsRender.

Details Page

The Details page is used to show the details about a single company. It takes a JSON object from the /Company/Details page and loads the JSON object in the HTML template. The Details page used in this example is shown in the listing below:

<html>
<head>
    <title>Displaying details of the single JSON object</title>
    <link rel="stylesheet" type="text/css" href="/Content/style.css" />
    <script src="/scripts/jQuery-1.4.4.min.js")" type="text/javascript"></script>
    <script src="/scripts/jQuery.loadJSON.js")" type="text/javascript"></script>
    <script language="javascript" type="text/javascript">
        $(document).ready(function () {
        var id = window.location.href.match("(ID=|id=|/)[0-9]+")[0].match("[0-9]+");
            $('div#data').loadJSON('/Company/Data/'+id);
        });
    </script>
</head>
<body>
<div id="page-wrap">
    <div id="contact-area">
    <div id="data">
          <h1 id="Name"></h1>
              <img id="Logo" alt="" src=""/>
          <label for="Address">Address:</label>
              <span id="Address"></span>
          <label for="Contact">Contact by:</label>
              <span id="Contact"></span>
          <label for="Town">Town:</label>
              <span id="Town"></span>
           <form action="edit.html" method="get">
              <input type="hidden" id="ID" name="ID"/>
              <input type="submit" value="Edit" class="submit-button"/>
           </form>
        </div>
    </div>
</div>
</body>
</html>

The page contains a definition of blank HTML templates with elements that have id attributes that match properties from the model. The JavaScript call in the heading takes the ID parameter from the page URL and calls the /Company/Details server-side page with that parameter, as shown in the following code example:

var id = window.location.href.match("(ID=|id=|/)[0-9]+")[0].match("[0-9]+");
$('div#data').loadJSON('/Company/Data/'+id);

The controller action Details(int? ID) in CompanyController will be called when this URL is sent to the server, and a single company will be returned as a JSON result. This JSON object will be loaded in the DIV with the "data" ID and elements in that DIV will be populated. You can see a live example of the Details page here. An example of the generated view for one company in the sample project is shown in the figure below:

Alternative Implementation using the Pure Templating Engine

Similar to the previous example, instead of loadJSON, any other templating engine can be used. As an example, if the Pure templating engine is used, the template can be the same as the one shown in the code sample (Pure uses the same clean HTML code as loadJSON). The JavaScript initialization call is shown in the following example:

var id = window.location.href.match("(ID=|id=|/)[0-9]+")[0].match("[0-9]+");
$.getJSON('/Home/Populate/'+id, function (company) {
    $("'div#data'").render(company, {  '#Name': 'Name', '#Address': 'Address',
                                       '#Logo@alt': 'Name', '#Logo@src':'Logo' });
});

In the example above, an AJAX call that loads the JSON object from the /Home/Populate/<<id>> URL is performed, and in the callback function, the JSON object is loaded into the div with ID 'data', as in the previous example. The second parameter of the Render function is a directive that maps HTML elements to JSON properties. In the directive shown in the example above, the Name and Address properties of the JSON object are loaded in the elements with ids Name and Address. In the alt attribute of the element with id 'Logo' is loaded the Name, and in the src attribute of the element with ID 'Logo' is placed the Logo property of the JSON object. The advantage of Pure is that you can define custom mapping rules between elements, their attributes, and properties of the JSON object. If you don't want to use directives, you can use the .autoRender() function instead of .render(). The function .autoRender() is similar to the .loadJSON() function shown in the example above; however, the .autoRender() function matches elements with properties by class name only (this is a "default directive" in the Pure templating engine).

Editing Details

The Edit page is similar to the Details page. However, here, a single company record is loaded into the HTML form. An example of the Edit page is shown in the following listing:

<html>
<head>
    <title>Load Form with JSON data</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <link rel="stylesheet" type="text/css" href="/Content/style.css" />
    <script src="/scripts/jQuery-1.4.4.min.js")" type="text/javascript"></script>
    <script src="/scripts/jQuery.loadJSON.js")" type="text/javascript"></script>
        <script language="javascript" type="text/javascript">
            $(document).ready(function () {
             var id = window.location.href.match("(ID=|id=|/)[0-9]+")[0].match("[0-9]+");
             $('form').loadJSON('/Company/Data/' + id);
            });
        </script>
</head>
<body>
<div id="page-wrap">
    <div id="contact-area">    
        <form name="form_simple" id="form-simple" action="details.html" method="get">
            <input type="hidden" id="ID" name="ID" />
        <label for="Name">Name</label>
        <input name="Name" id="Name" type="text" />
        <label for="Address">Address</label>
        <textarea name="Address" id="Address" rows="5" cols="20"></textarea>
        <label for="Country">Country</label>
        <select name="Country" multiple="multiple">
                    <option value="">-</option>
            <option value="UK">United Kingdom</option>
                    <option value="SRB">Serbia</option>
            <option value="USA">United States of America</option>
            <option value="FRA">France</option>  
        </select>
        <label for="IsFeatured">Is Featured</label>
        <input name="IsFeatured" id="IsFeatured" type="checkbox" value="true"/>
        <label for="Town">Town</label>
        <select name="Town" id="Town">
                    <option value="" selected="selected">-</option>
            <option value="London">London City</option>
            <option value="Liverpool">Liverpool City</option>
            <option value="Lothian">Lothian City</option>
            <option value="Newcastle">Newcastle City</option>
                    <option value="Buckinghamshire">Buckinghamshire City</option>
                    <option value="Essex">Essex City</option>  
        </select>
        <label for="Contact">Contact</label>
            <input name="Contact" type="radio" value="Email"/> Email
            <input name="Contact" type="radio" value="Phone" /> Phone
            <input name="Contact" type="radio" value="Post" /> Post
                <input type="submit" value="Details" class="submit-button" />
    </form>
    </div>
</div>
</body>
</html>

The heading should contain a JavaScript call that loads the JSON object from the URL into the form. This JavaScript call is shown in the following code:

var id = window.location.href.match("(ID=|id=|/)[0-9]+")[0].match("[0-9]+");
$('form').loadJSON('/Company/Data/' + id); 

The result of this call is a form populated with properties of the JSON object loaded from the /Company/Data/<ID> URL. A live example of the form populated with the loadJSON plug-in can be found here and detailed rules that are used while populating the form are described here. An example of the form populated with JSON data is shown in the figure below:

JavaScript-View-Engine/loadJSON-edit.png

The jQuery loadJSON plug-in will check the type of each form element where the JSON properties should be loaded, and depending on the type, it will put the property as a text in text boxes and text areas, selected items in radio button groups, single, and multi selection lists, and checked/unchecked state in check boxes. In other plug-ins, you would need to manually set the mapping rules for loading form elements.

In other plug-ins, I have not found an equivalent simple implementation of populating forms, so this example will not be shown in any alternative implementations.

Hierarchical View

The last view shows how the complex/hierarchical structures can be rendered using client-side engines. The previous examples used simple structures (array of companies, single company), but as you might see in the model, there is a relation between Company and Employees. When the list of companies is returned by the Company/List action, the following structure is returned as a JSON result:

[
    {   "ID": 17, "Name": "Emkay Entertainments", 
        "Address": "Nobel House, Regent Centre",
        "Town": "Lothian", "Contact": "Phone", "IsFeatured": true,
        "Manager": { "FirstName": "Nick", "LastName": "Donovan" },
        "Employees": [  { "FirstName": "John", "LastName": "Doe" },
                        { "FirstName": "Alex", "LastName": "Watkins" },
                        { "FirstName": "Mick", "LastName": "Henning"}]
    },
    {   "ID": 18, "Name": "The Empire", "Address": "Milton Keynes Leisure Plaza",
        "Town": "Buckinghamshire", "Contact": "Post", "IsFeatured": false,
        "Manager": { "FirstName": "Ana", "LastName": "Frank" },
        "Employees": [  { "FirstName": "Mark", "LastName": "Anderson" },
                        { "FirstName": "John", "LastName": "Haus" },
                        { "FirstName": "Sinthia", "LastName": "Clouny"}]
    } 
]

As you can see, in the array of companies that is returned, for each company object, both simple properties (Name, Address, etc.) and a nested object Manager and a nested array Employees are returned. Nested structures can also be displayed using client-side engines.

If loadJSON is used, the HTML template should have nested elements that match the structure of the returned JSON response. An example of an HTML template that can be used with the loadJSON plug-in is shown in the listing below:

<ol>
    <li>
        <div class="divEmployees">
        <h3>Employees <img class="closed" 

            src="/Content/images/details_open.png" alt="open/close"/></h3>
        <dl class="Employees"> 
            <dt class="FirstName"></dt><dd class="LastName"></dd>
        </dl>
        </div>
        <a href="details.html" class="ID">
            <span class="Name"></span></a>
        <span class="Address"></span>
        <h3>Manager:</h3>
            <span class="Manager">
                <span class="FirstName"></span> <span class="LastName"></span>     
            </span>
    </li>
</ol>

In the template are placed placeholders for the company fields (ID, Name, Address) as in the list example. There is a placeholder Manager (in the SPAN tag) for the reference to the manager object that has two placeholders for the manager's first name and last name. Also, there is a place holder for the Employees array in the DL tag where the array of Employee objects associated to the company via the "Employee" array will be loaded. In that placeholder, nested placeholders for the first name and last name of each employee that is returned in the nested array are placed. When a JSON object is loaded in this template using the loadJSON function, a nested structure of the element (moved to the right side) is generated as shown in the following figure:

JavaScript-View-Engine/loadJSON-hierarchy-view.png

On the first level, companies in the ordered list are listed, where basic company details and the nested manager object are shown. For each company, a nested list of the employees that work for the company is generated. In the screenshot above, employees for the first and fourth company are expanded while the others are collapsed. You can see a live example here, but without buttons for showing/hiding employees. The functionality for showing/hiding the nested lists of employees is implemented using custom JavaScript that is not part of the templating engine - you can find more details about this script below.

Alternative Implementation Using the Pure Templating Engine

Instead of loadJSON, you can use any other templating engine. If you use Pure, the same HTML template can be used but you will need to define mapping rules between the hierarchical template and the JSON object that is returned from the server-side. If Pure engine is used, the following script generates the view:

 $.getJSON('/Company/List', function (data) {
    $("ol").render(data, {
        li: {
            'company<-': {
                '.ID': 'company.Name',
                '.ID@href': 'company.ID',
                '.Address': 'company.Address',
                '.Manager .FirstName': 'company.Manager.FirstName',
                '.Manager .LastName': 'company.Manager.LastName',
                'dl.Employees': {
                    'employee<-company.Employees': {
                        '.FirstName': 'employee.FirstName',
                        '.LastName': 'employee.LastName'
                        }
                    }
                }
            }
    });
});

In this example, the JSON object is taken from the '/Company/List' URL and the returned JSON object is rendered into the OL element that contains the template. The only difference is the directive that explicitly defines the mapping rules - I will try to explain the directive that is used in this example. The Render function finds an li element and iterates over the array that is returned by the 'company<-' directive. Each object in the loop will be identified as a 'company'. In the elements with classes ID and Address, the company.Name and company.Address fields from the array are placed, and in the attribute href of the link with class "ID" is placed the ID of the companies. In the elements with classes "FirstName" and "LastName" that are placed within the element with class "Manager" are placed company.Manager.FirstName and company.Manager.LastName (properties of the nested object manager).

The inner list is generated using the last statement in the directive. In the DL element with class "Employees" is applied a loop over the array company.Employees - each element in the loop is identified using the 'employee' identifier. In the elements DT and DD with classes "FirstName" and "LastName" that are placed inside the DL element are placed the employee.FirstName and employee.LastName properties of the JSON objects.

The Pure engine is a more powerful templating engine than the loadJSON plug-in because it has complex directives that enable you to customize mapping rules exactly how you need them. However, as you can see, you will need to learn the syntax that is used for the directives to be able to customize the rendering rules. An explanation of the syntax is not part of this article (this was just a specific example) so if you are interested in this, please find more details about the syntax at the Pure site.

Applying Custom JavaScript Code

Note that the view engine gives you just a static HTML structure - if you need some interaction, you can add a custom function to this structure. As an example, in this view, functionality is added that opens and closes the nested employees list each time the user clicks on the image. An example of the code for showing/hiding a nested list is shown in the following listing:

$("dl.Employees").hide();
$(".closed").click(function (item) {
    if ($(this).hasClass("closed")) {
        this.src = "/Content/images/details_close.png";
        $(this).removeClass("closed");
        $("dl", $(this).parents("li")).fadeIn("slow");
    } else {
        this.src = "/Content/images/details_open.png";
        $(this).addClass("closed");
        $("dl", $(this).parents("li")).fadeOut("slow");
    }
});

This code initially hides all the nested employees and attaches the click handler on the image where employees for the selected company are shown/hidden depending on the state. This is completely independent of the template engine code, so the same functions can be used with different view engines as long as they generate identical output. There are no constraints in this approach; as long as you know what structure you need, you can apply any JavaScript code on the structure that is generated by the templating engine. Instead of the custom code, you can also apply some of the existing plug-ins that will continue to handle interaction with client.

As an example, if you need an expandable table, you can use the DataTables plugin that already handles most of the common functionalities you need. In this case, templating engines can be used to generate the initial HTML structure required by the DataTables plug-in, and then you can apply this plug-in on the generated structure and let the plug-in handle all further custom interactions.

Conclusion

This article explains how the loadJSON plug-in can be used as a client-side templating engine, and it shows how JSON objects can be loaded directly in the HTML elements on the client side. There are several benefits of using client-side templating engines:

  1. Performance - loading JSON objects from the server side, only a minimal amount of data is transferred from the server to the client side. This way, it is not required to load unnecessary HTML tags from the server and the time required to load data is shorter.
  2. Caching - the example uses static HTML pages as views. Therefore, if active views (e.g., .aspx pages) are used instead, they can be cached on the server side. This makes the server-side response time shorter.
  3. True separation of design and code - using server-side templating engines, the code placed in the view is not completely clean. The HTML code contains some elements that are required for binding server side data to the view elements. The examples in this article show that the view is completely clean - there is nothing else except the HTML code in the view pages (not even custom attributes).

However, this is not a "Holy Grail" of web development as it does not resolve all your problems, nor does it represent the perfect solution. If you have some complex logic you need to place in the view, e.g., determine whether some element should be disabled or hidden, or if you need to dynamically show/hide some elements, you cannot implement this using simple client-side view engines. In such cases, it is better to retain server-side code data because it will be easier to control it via code, partial views, and server-side controls. However, applying client-side view engines (when this is appropriate) would bring you several benefits as explained above.

In this example, the loadJSON plug-in is used because it is the simplest plug-in that can be used and is the most appropriate for the presentation of client-side view engine concepts. However, you can use any other templating engine and the approach will be similar. Other templating engines I recommend are: 

  1. jsRender - this is a successor of the deprecated jQuery templates which were part of the standard jQuery API.
  2. Pure - an excellent templating engine that provides a complex language for defining rules for matching elements in the template with a JSON data source. The drawback of this engine is that you will need to learn the templating language used in directives that define how data is bound to the template. 
  3. Knockout - the most advanced template I found with support for binding, change tracking/update of JSON model, etc. If you want full control with your template engine, I would recommend this one.

There is no best templating engine and each of the engines mentioned in this article have both advantages and disadvantages. The major advantage of the loadJSON plug-in is its simplicity and ability to correctly populate form elements without specifying any rules for mapping. However, the same thing can be achieved in other templating engines with more or less effort.

History

  • 28th April, 2011: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here