Wednesday, November 23, 2011

Parsing XML and databinding using jsRender and jsViews (RIP jQuery Templates)

I have always been a huge fan of the very flexible ASP.NET ListView control for creating templates and databinding nested data collections. Recently though I have been making a stronger effort to work with client side technologies like jQuery and client friendly data formats like JSON and JSONP. Thanks to the hard work of Microsoft’s Boris Moore, a new technology called jQuery Templates was put into beta as an official plugin and a CDN was created in jQuery and Microsoft. Unfortunately after spending some time studying the framework, I learned that it had been deprecated, “rebranded” as jsRender and jsViews, and a tentative schedule to add it to the jQuery UI framework (at least the jsRender portion). Fortunately, the new framework still has support, has improved performance, and a syntax that hasn’t changed too much. This is really a useful technology, so hopefully it will get adopted soon as a first class jQuery plugin or independent framework.
jsRender Databinding SyntaxThe first line initializes the template object. The object is then rendered with the data and appended to an html element.
$("#tblTemplate").template("tblTemplate");
$("#tblBod").append($.render(obj, "tblTemplate"));


jsViews Template SyntaxThis first table element sets up the html part of the template which will be used to append the data to. Conceptually this is the same as the ASP.NET ListView’s LayoutTemplate element. You then create a script element of type “text/x-jquery-tmpl” and use jsViews markup syntax to create the template. You can then render the object directly or by using conditional statements. For nested objects you can use “each” statements. This is conceptually like the ASP.NET ListView control’s ItemLayout element. See Dan Wahlin’s article for more information on using this syntax.

<table id="tbl">
   <
thead>
      <
tr>
         <
th>Name</th>
         <
th>Example</th>
      </
tr>
   </
thead>
   <
tbody id="tblBod" />
</
table>
<script
id="tblTemplate" type="text/x-jquery-tmpl">    <tr>
      <td><div class='name-value'>{{=name}}</div>
         {{#if $data.returnVal}}
            <div class='info-value'>Return: {{=returnVal}}</div>
         {{else}}
            <div class='info-value'>Return: N/A</div>
         {{/if}}
         {{#if $data.category}}
            <div class='info-value'>Category: {{=category}}</div>
         {{/if}}
      </td>
      <td>
         <div class='desc-value'>{{=desc}}</div>
         <pre>{{=example}}</pre>
      </td>
   </tr>
</script>In my example below, I decided to use a good sized XML file (1 MB) which represents the jQuery API and is found on jQuery.com. Parsing, sorting, and rendering the XML only took about 2 seconds. Generally you would use AJAX to return some data from a web service or REST service instead, but I wanted to see how easy it was to parse XML with jQuery.

Instructions:
1. Copy and paste the following an html file.
2. Save the xml from http://api.jquery.com/api as jqueryapi.xml.
3. Save the jsrender.js from https://github.com/BorisMoore/jsrender
4. Save the jquery.views.js from https://github.com/BorisMoore/jsviews
5. Run the code!

Screenshot

image


Source Code:

<!DOCTYPE html>
<
html>
<
head>
    <
title>jQuery: Parsing XML / jsrender and jsviews</title>
    <
style>
      
body
      
{
            font-family: Verdana;
            font-size: 12px;
        }
        #tbl
      
{
            border: solid 1px silver;
            border-collapse: collapse;
        }
        #tbl th
      
{
            font-size:14px;
        }
        .name-value
      
{
            font-size: 14px;
            font-weight:bold;
            padding-bottom: 10px;
        }    
        .info-value
      
{
            padding-left:10px;
            font-style:italic;
        }  
        th, td
      
{
            border: solid 1px silver;
            text-align: left;
            padding: 6px;
            vertical-align: top;
        }
        pre
      
{
            white-space: pre-wrap;
        }
    </style>
    <
scriptsrc="http://code.jquery.com/jquery.min.js"></script>
    <
scriptsrc="jsrender.js"></script><!--Currently no CDN available: https://github.com/BorisMoore/jsrender-->
  
<scriptsrc="jquery.views.js"></script><!--Currently no CDN available: https://github.com/BorisMoore/jsviews-->
  
<script>
      
$(function($) {
            //XML comes from: http://api.jquery.com/api/
          
$.get('jqueryapi.xml', 'xml').done(function(data) {
                var $foods = $(data).find("entry");
                var obj = [];
                var keys = newArray();
                keys[0] = newArray("attribute", "name", "name");
                keys[1] = newArray("attribute", "returnVal", "return");
                keys[2] = newArray("childtext", "desc", "desc:first");
                keys[3] = newArray("childtext", "example", "example > code");
                keys[4] = newArray("childattribute", "category", "category:first", "name");
                $foods.each(function(idx, elem) {
                    var $this = $(this), data = {};
                    keys.forEach(function(key) {
                        switch(key[0]) {
                            case'attribute':
                                data[key[1]] = $this.attr(key[2]);
                                break;
                            case'childtext':
                                data[key[1]] = $this.find(key[2]).text();
                                break;
                            case'childattribute':
                                data[key[1]] = $this.find(key[2]).attr(key[3]);
                                break;
                        }
                    });
                    obj.push(data);
                });
                obj.sort(sort_by('category', 'name'));
                $("#tblTemplate").template("tblTemplate");
                $("#tblBod").append($.render(obj, "tblTemplate"));
            }).error(function(data) {
                console.log('fail', data);
            });
        });

        //Sorting algorithm courtesy of Felix Kling: http://stackoverflow.com/questions/6913512/how-to-sort-an-array-of-objects-by-multiple-fields
      
var sort_by;
        (function() {
            var default_cmp = function(a, b) {
                if(a == b) return0;
                returna < b ? -1 : 1;
            },
                getCmpFunc = function(primer, reverse) {
                    var dfc = default_cmp,
                        cmp = default_cmp;
                    if(primer) {
                        cmp = function(a, b) {
                            returndfc(primer(a), primer(b));
                        };
                    }
                    if(reverse) {
                        return function(a, b) {
                            return-1 * cmp(a, b);
                        };
                    }
                    returncmp;
                };
            sort_by = function() {
                var fields = [],
                    n_fields = arguments.length,
                    field, name, reverse, cmp;
                for(var i = 0; i < n_fields; i++) {
                    field = arguments[i];
                    if(typeof field === 'string') {
                        name = field;
                        cmp = default_cmp;
                    }
                    else{
                        name = field.name;
                        cmp = getCmpFunc(field.primer, field.reverse);
                    }
                    fields.push({
                        name: name,
                        cmp: cmp
                    });
                }
                return function(A, B) {
                    var a, b, name, result;
                    for(var i = 0, l = n_fields; i < l; i++) {
                        result = 0;
                        field = fields[i];
                        name = field.name;
                        result = field.cmp(A[name], B[name]);
                        if(result !== 0) break;
                    }
                    returnresult;
                }
            }
        } ());           
    </script>
</
head>
<
body>
    <
tableid="tbl">
        <
thead>
            <
tr>
                <
th>Name</th>
                <
th>Example</th>
            </
tr>
        </
thead>
        <
tbody id="tblBod" />
    </
table>
    <
scriptid="tblTemplate"type="text/x-jquery-tmpl">
      
<tr>
            <td><div class='name-value'>{{=name}}</div>
               {{#if $data.returnVal}}
                    <div class='info-value'>Return: {{=returnVal}}</div>
               {{else}}
                    <div class='info-value'>Return: N/A</div>
               {{/if}}
               {{#if $data.category}}
                    <div class='info-value'>Category: {{=category}}</div>
               {{/if}}
            </td>
            <td>
                <div class='desc-value'>{{=desc}}</div>
                <pre>{{=example}}</pre>
            </td>
        </tr>
    </script>
</
body>
</
html>

Resources

github – jsrenderhttps://github.com/BorisMoore/jsrender

github – jsviewshttps://github.com/BorisMoore/jsviews
jQuery Templates and JsViews: The Roadmaphttp://www.borismoore.com/2011/10/jquery-templates-and-jsviews-roadmap.html
Reducing JavaScript Code Using jsRender Templates in HTML5 Applicationshttp://weblogs.asp.net/dwahlin/archive/2011/11/23/reducing-javascript-code-by-using-jsrender-templates-in-html5-applications.aspx

7 comments:

  1. Nice site services. I arrived utilizing your favorite article though “blog site surfing” generating the exact Next ideas control key upon several Nav Bar situated throughout specific upper at my very own blogger.com website. i do generally recently travelling approximately viewing on other types of personal blogs which actually live over of the on the web, as well as up many, creative steps while which also people indicate their particular own. thankfully to giving.

    ReplyDelete

  2. Hi guys, I have the working crack/SERIAL KEYS for Internet Download Manager which works in all versions, the crack is lifetime and I am using it for quite some time now. I will share it to you below..
    Download Crack IDM 6.23 build 15 Full
    Crack IDM 6.23 Full Free Download IDM 6.23 build 15 Full Crack Patch
    jailbreak ios 8.4

    ReplyDelete
  3. I have been following you for a couple of months now but this is my first time commenting on a blog post. Thank you for sharing your knowledge and experience with us. Keep up the good work. Already bookmarked for future reference.
    Hadoop Training in Chennai
    Hadoop Training
    Best Hadoop Training in Chennai
    Best Hadoop Training Institute in Chennai

    ReplyDelete
  4. I just see the post i am so happy the post of information's.So I have really enjoyed and reading your blogs for these posts.Any way I’ll be subscribing to your feed and I hope you post again soon.

    digital marketing course in chennai
    software testing training in chennai

    ReplyDelete
  5. QuickBooks Support :+1855-686-6166

    QuickBooks Technical Support team at +1-855-686-6166 you can get the best answers for all the problems in QuickBooks. This software provides you tools that are extremely beneficial for almost every industry type in the world.Quickbooks Support Phone Number+1-855-686-6166 can fix all issues which are relate with quickbooks pro, quickbooks premier, quickbooks enterprise, quickbooks pos or quickbooks accountant. We have 24*7 support team for,

    QuickBooks Pro
    QuickBooks Premier
    QuickBooks Enterprise
    QuickBooks Point of Sale
    QuickBooks Payroll
    QuickBooks Accountant

    Several mind-blowing features are contained by each of these versions. Any hindrance caused by any QuickBooks error is taken care of by our QuickBooks Support team.

    ReplyDelete