본문 바로가기

Javascript/Jquery

HTML5 Application에서 JsRender Template사용하기

http://weblogs.asp.net/dwahlin/archive/2011/11/23/reducing-javascript-code-by-using-jsrender-templates-in-html5-applications.aspx

위의 기사를 퍼온 글입니다.


imageBack in November of 2010 I wrote a post titled Reducing Code using jQuery Templates that demonstrated how jQuery Templates could be used to reduce significant amounts of JavaScript code. Although the topics and code discussed in that post are still valid and relevant in today’s applications, things have a changed some when it comes to the future of jQuery Templates. I’ve had questions come up in the jQuery classes that we offer, at conferences, and online about the future of jQuery Templates so I thought I’d put a post together that provides updated information.

To get the full story you can read Boris Moore’s blog, but in a nutshell the jQuery UI team decided to go a different direction with client-side templates and use an alternate syntax. As a result, a new script has been released called jsRender that will ultimately replace jQuery Templates - at least that’s the current plan. I’ll review a few things mentioned in my initial post here for those that aren’t familiar with templates and then show examples of using the new jsRender functionality in an application.

Nearly every language out there uses templates in some manner to minimize the amount of code that has to be written. By using templates you can define a template structure once and use it to generate code, HTML or other formats. If you’ve created ASP.NET applications then you’re aware of how powerful and productive templates are when it comes to generating HTML output. However, what if you want to use templates on the client-side to generate HTML rather than writing a lot of JavaScript to manipulate the DOM?

Although templates have been available in jQuery for quite awhile through various plug-ins, the jsRender template framework provides a new solution that doesn’t use CSS in strange ways or require a lot of knowledge about a template language. By using it you can define HTML templates in web pages and use them to render HTML output dynamically at runtime. You can download the jsRender script along with samples from https://github.com/BorisMoore/jsrender.

Defining a Template Block

You can use client-side templates by referencing the jsRender script mentioned above and then defining a <script> block in your page with a type of text/x-jquery-tmpl as shown next:

 

<script id="OrderSummaryTemplate" type="text/x-jquery-tmpl">
<!-- Template goes here –>
</script>

 

Once the script tag is defined you can place template code inside of it. Any HTML you add into the template is output automatically once the template is rendered. Of course, adding static HTML doesn’t accomplish much so jsRender provides several tags that can be placed inside of a template to define data that should be output, perform conditional logic, iterate through items, render nested templates, plus more. The key template tags available with jsRender are shown next:

Template Tag Example Description
{{=fieldNameOrExpression}}
{{=DeliveryFee}}
Used to define data values that should be rendered in the template. Evaluates the specified property on the current data item and encodes the value.
{{=fieldNameOrExpression!}}
{{=Comments!}}
Used to define HTML markup strings that should be rendered by the template (notice that a ! character is placed at the end of the string). Evaluates the specified field on the current data item and doesn’t encode the value.
{{#if condition}}
{{#if DeliveryFee > 0}}
{{=DeliveryFee}} added to your order.
{{/if}}
Used for conditional insertion of content.
{{else}}
{{#if MainItems.length===0}}
    <tr>
        <td>No items selected</td>
    </tr>
{{else}}
<tr>
<td>Ordered items!</td>
</tr>   
{{/if}}
Used to add additional conditional logic into jsRender templates.
{{#each}}
{{#each MainItems}}
    <tr>
        <td>
            {{=mi.NumberOrdered}} ordered
at ${{=mi.Price}} per item
        </td>
    </tr>
{{/each}}
Used to iterate over a data array and render the content for each data item.
{{#each tmpl=”#NestedTemplateID”}}
<script id="movieTemplate" type="text/x-jquery-tmpl"> 
    {{#each Movies tmpl="#titleTemplate"}}
</script>

<script id="titleTemplate" type="text/x-jquery-tmpl"> 
    <tr class="title">
<td>{{=Name}}</td>
</tr> </script>
Used for composition of templates. Renders one or more nested template items within the rendered output of the parent template.

 

Rendering a Template

Once a template is defined using a <script> block you can use jsRender’s render() function to convert JSON data into into HTML based upon the template. This is done by identifying the target element that will host the content, calling its html() function (when using jQuery). and then passing the HTML that’s generated by calling the render() function. The render() function accepts the JSON data that the template will use to generate HTML content. An example of putting all of this together is shown next. You’ll see that the OrderSummaryOutput element is located in the DOM using a jQuery selector and that its html() function is passed the output generated by a jsRender template.

 

$("#OrderSummaryOutput").html($("#OrderSummaryTemplate").render(json));

 

The JSON data can be created locally or retrieved from a remote service call as shown next:

 

$.ajax({
    dataType: 'jsonp',
    url: moviesServiceUrl,
    jsonp: '$callback',
    success: showMovies
});

// Within the callback, use .tmpl() to render the data.
function showMovies(data)
{
    // Render the template with the "movies" data and insert
    // the rendered HTML under the 'movieList' element
    $("#movieList").html($("#moviesTemplate").render(data));
}

 

jsRender in Action

A sample application that I created to demonstrate jsRender in action can be downloaded here (it’s part of the sample code available with our jQuery Web Programming training course). The sample app is an ASP.NET MVC 3 project named “Order Up” that leverages jQuery heavily and uses jsRender to display order details. An example of the output that’s rendered is shown next:

image


The template used to generated the Totals, Delivery Information, Items Ordered and Accessories Ordered sections is shown next:

 

<script id="OrderSummaryTemplate" type="text/x-jquery-tmpl">
    <table style="width:100%;">
        <tbody>             
            <tr>
                <td class="OrderHeader">Totals:</td>                    
            </tr>                    
            <tr>
                <td style="font-size:12pt;">
                    <table style="width:400px;">
                        <tr>
                            <td style="width:50%;">Sub Total:</td>
                            <td>$<span id="FinalSubTotal">{{=FinalSubTotal}}</span></td>
                        </tr>
                        <tr>
                            <td style="width:50%;">Sales Tax:</td>
                            <td>$<span id="FinalSalesTax">{{=FinalSalesTax }}</span></td>
                        </tr>
                        {{#if DeliveryFee > 0}}
                            <tr>
                                <td style="width:50%;">Delivery Fee:</td>
                                <td>$<span id="FinalDeliveryFee">{{=DeliveryFee }}</span></td>
                            </tr>
                        {{/if}}
                        <tr>
                            <td style="width:50%;">Admin Fee:</td>
                            <td>$<span id="FinalAdminFee">{{=AdminFee }}</span></td>
                        </tr>
                        <tr style="border-top:1px solid black;">
                            <td style="width:50%;font-weight:bold;">Total:</td>
                            <td>$<span id="FinalTotal">{{=FinalTotal }}</span></td>
                        </tr>   
                        <tr>
                            <td colspan="2">&nbsp;</td>
                        </tr>
                        <tr>
                            <td colspan="2">Will be charged to your credit card ending with {{=CreditCard }}</td>
                        </tr>                     
                    </table>                        
                </td>
            </tr> 
            <tr>
                <td>&nbsp;</td>
            </tr> 
            <tr>
                <td class="OrderHeader">Delivery Information</td>                    
            </tr>
            <tr>
                <td>
                    <table style="width:500px;">
                        <tr>
                            <td style="width:25%;">Deliver To:</td>
                            <td>{{=DeliveryName}}</td>
                        </tr>
                        <tr>
                            <td style="width:25%;">Address:</td>
                            <td>{{=DeliveryAddress}}</td>
                        </tr>
                        <tr>
                            <td style="width:25%;">Date and Time:</td>
                            <td>{{=DeliveryDate}} from {{=DeliveryTime}}</td>
                        </tr>                        
                    </table>                         
                    </td>
            </tr>
            <tr>
                <td>&nbsp;</td>
            </tr>                    
            <tr>
                <td class="OrderHeader">Items Ordered</td>
            </tr> 
            {{#if MainItems.length === 0}}
                <tr>
                    <td>No items selected</td>
                </tr>
            {{else}}
                {{#each MainItems tmpl="#ItemsTemplate"}}
            {{/if}}
            <tr>
                <td>&nbsp;</td>
            </tr>   
            <tr>
                <td class="OrderHeader">Accessories Ordered</td>
            </tr> 
            {{#if AccessoryItems.length === 0}}
                <tr>
                    <td>No accessories selected</td>
                </tr>
            {{else}}
                {{#each AccessoryItems tmpl="#ItemsTemplate"}}
            {{/if}}
            <tr>
                <td>&nbsp;</td>
            </tr>                          
        </tbody>
    </table>    
</script>

<script id="ItemsTemplate" type="text/x-jquery-tmpl">
    <tr>
        <td>
            {{=Name}} - {{=NumberOrdered}} ordered at $ {{=Price}} per item
        </td>
    </tr>
</script>
 

The template is rendered to a div with an ID of OrderSummaryOutput using the following code.  The code first creates a JSON object by retrieving data from controls in a checkout wizard and then calls the the render() function provided by jsRender.

 

function LoadApprovalDiv() {
    var subTotal = parseFloat($('#SubTotal').text());
    $('#ClientSubTotal').val(subTotal.toFixed(2));
    var salesTaxRate = parseFloat($('#SalesTaxRate').val()) / 100;
    var salesTaxAmount = (subTotal * salesTaxRate) * .9;
    var deliveryFee = parseFloat($('#DeliveryFee').val());
    var adminFee = ((subTotal + salesTaxAmount + deliveryFee) * .05);
    var total = (Round(subTotal) + Round(salesTaxAmount) + Round(deliveryFee) + 
                 Round(adminFee));
    $('#ClientTotal').val(total);
    var deliveryAddress = $('#Delivery_Street').val();
    //See if they entered a suite
    if ($('#Delivery_Suite').val() != '') deliveryAddress += ', Suite ' + $('#Delivery_Suite').val();
    deliveryAddress += ' ' + $('#Delivery_City').val() + ' ' + $('#Delivery_StateID option:selected').text() + ' ' + 
                       $('#Delivery_Zip').val();
    var creditCard = $('#Payment_CreditCardNumber').val();
    var abbrCreditCard = '*' + creditCard.substring(creditCard.length - 5);

    var json = {
                   'FinalSubTotal'  : subTotal.toFixed(2),
                   'FinalSalesTax'  : salesTaxAmount.toFixed(2),
                   'FinalTotal'     : total.toFixed(2),
                   'DeliveryFee'    : deliveryFee.toFixed(2),
                   'AdminFee'       : adminFee.toFixed(2),
                   'DeliveryName'   : $('#Delivery_Name').val(),
                   'DeliveryAddress': deliveryAddress,
                   'CreditCard'     : abbrCreditCard,
                   'DeliveryDate'   : $('#Delivery_DeliveryDate').val(),
                   'DeliveryTime'   : $('#Delivery_DeliveryTime option:selected').text(),
                   'MainItems'      : GenerateJson('Main'),
                   'AccessoryItems' : GenerateJson('Accessory')
               };

    //jQuery template example
    $("#OrderSummaryOutput").html($("#OrderSummaryTemplate").render(json));
}


If you’re working with dynamic web applications that leverage jQuery and AJAX you’ll find that jsRender can significantly increase your productivity and eliminate a lot of code that you’d normally have to write. Although jsRender is still new (at the time this post was written anyway), it’s definitely worth looking into more. In future posts I’ll discuss a companion to jsRender called jsView that provides client-side data binding capabilities.

 

If you or your company is interested in training, consulting or mentoring on jQuery, HTML5,  or .NET technologies please visit http://www.thewahlingroup.com for more information. We’ve provided training, consulting and mentoring services to some of the largest companies in the world and would enjoy sharing our knowledge and real-world lessons learned with you.