📜 ⬆️ ⬇️

We work with jQuery Templates

Introduction


The jQuery Templates plugin is a “template engine” that works on the client side as a jQuery extension.

This plugin helps to show data in the browser in JavaScript objects and arrays, saving you from the routine operations of creating HTML-code, escaping special characters, etc. In addition, it has very interesting features - for example, it allows you to update the HTML code created with it when the source data changes.

Of course, jQuery Templates is not the only and not the first “template engine”, but it has a big advantage over alternative options - support from the jQuery Team . This allows us not to be afraid of the fact that this plugin will be abandoned, and various problems that arise when new versions of browsers are released will have to be resolved on our own.
')
In this article, I will discuss the main features of jQuery Templates and demonstrate its work in various scenarios, and in subsequent articles I will discuss functions not included in the core code of the plugin ( jQuery Templates Plus ) and on the extension of the template language.


A bit of history


This plug-in was developed by Microsoft’s JavaScript- based Micro-templating library (by John Resig ), some details about the development can be found in Stephen Walther ’s blog post “ An Introduction to jQuery Templates ” and from John Resig ’s Templating Syntax post on jQuery forum. Since last October, jQuery Templates , jQuery DataLink, and jQuery Globalization plug-ins have become part of the jQuery project .

Part one, theoretical


Getting Started


Let's start. The following example shows the list of movies specified in the array (the full code for the example is in the BasicSample1.htm file):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>  (1)</title> <link href="Styles/Default.css" rel="Stylesheet" type="text/css" /> <script src="Scripts/jquery-1.5rc1.js" type="text/javascript"></script> <script src="Scripts/jquery.tmpl.js" type="text/javascript"></script> <script src="DataItems.js" type="text/javascript"></script> <script id="movieTmpl" type="text/x-jquery-tmpl"> <div class="movie-bag"> <img src="Content/Thumbnails/${thumbnail}" class="thumbnail" /> <div class="base-info"> <h2> ${title} </h2> <p> : ${director}<br />  : ${actors}<br /> : ${year} </p> </div> </div> </script> <script type="text/javascript"> $(function () { $('#movieTmpl').tmpl(dataItems).appendTo('#movieListBag'); }); </script> </head> <body> <h1>  (1)</h1> <div id="movieListBag"> </div> </body> </html> 

But what you see in the browser:



Let's analyze this example in detail.

So the first thing I do is connect the jQuery Core Library and jQuery Templates :

 <script src="Scripts/jquery-1.5rc1.js" type="text/javascript"></script> <script src="Scripts/jquery.tmpl.js" type="text/javascript"></script> 

It has been repeatedly stated that jQuery Templates will be included in the jQuery Core Library - but in jQuery 1.5 RC1, released on January 24, there are still no templates.

Then I upload a list of movies:

 <script src="DataItems.js" type="text/javascript"></script> 

Of course, you can prepare the source data in any way that is convenient for you - get it using an AJAX request, create it based on user input, etc., I use the static script only as an example.

Inside the DataItems.js file looks like this:

 var dataItems = [ { title: '', thumbnail: 'Bandits.jpg', director: ' ', actors: [' ', '  ', ' '], year: 2001, budget: 95000000, grossRevenue: 67631903, rating: 0, frames: ['Bandits-1.jpg', 'Bandits-2.jpg', 'Bandits-3.jpg', 'Bandits-4.jpg', 'Bandits-5.jpg'] }, ... 

The next step I create the template:

 <script id="movieTmpl" type="text/x-jquery-tmpl"> <div class="movie-bag"> <img src="Content/Thumbnails/${thumbnail}" class="thumbnail" /> <div class="base-info"> <h2> ${title} </h2> <p> : ${director}<br />  : ${actors}<br /> : ${year} </p> </div> </div> </script> 

Please note that the template is placed in the SCRIPT tag, and as the MIME type, I specify text / x-jquery-tmpl . Having encountered an unfamiliar MIME type while parsing a document, the browser does not attempt to interpret the contents of the SCRIPT tag, which is what I need.

Generally speaking, a template can be placed in any tag, for example, in a DIV tag:

 <div id="movieTmpl" style="display: none"> <div class="movie-bag"> <img src="Content/Thumbnails/${thumbnail}" class="thumbnail" /> <div class="base-info"> <h2> ${title} </h2> <p> : ${director}<br />  : ${actors}<br /> : ${year} </p> </div> </div> </div> 

However, in this case, you can not avoid side effects, because the browser will definitely try to interpret the template code.

For example, for the example above, an attempt will be made to load a non-existent image:



But with the table, everything can be much more interesting (many thanks to TEHEK for this example!):

 <div id="movieTmpl" style="display: none"> <table> <tbody> {{each dataItems}} <tr> <td>${title}</td> <td>${director}</td> <td>${year}</td> </tr> {{/each}} </tbody> </table> </div> 

Internet Explorer and Opera will handle this code correctly:



But Chrome and Fire Fox "push" the extra code out of the table, resulting in a table that will be empty ... Happy debugging! ;-)



For the SELECT tag, a similar pattern will be observed.

I recommend placing templates in the DIV tags during development in order to take advantage of all the charms of IntelliSence and then move them to the SCRIPT tag.

Finally, I instantiate the template using the following call:

 $('#movieTmpl').tmpl(dataItems).appendTo('#movieListBag'); 

What happens when this happens, I depicted in the diagram below:



So:
  1. The .tmpl () method gets the template text - i.e. inner text of an element received by calling $ ('# movieTmpl') .
  2. The text of the template is compiled - on its basis a JavaScript function is created.
  3. A “template instance” is created - an object that contains a reference to a data element ( data field), passed as an argument to the .tmpl () method. The .tmpl () method can be passed an array, an object, null, or called without any arguments. If you pass an array, then for each element of the array you will create your own copy of the template that refers to this element, in all other cases only one instance will be created.
  4. The compiled template function is called, to which the instance object is passed. The function returns the text of the template in which all substitutions are made.
  5. The text obtained in the previous step is converted to a collection of HTML elements. References to these elements are also stored in the instance object (the nodes field), which makes it possible in the future to easily update the “output” of the template when the source data changes (see the Dynamic Update section).
  6. Finally, the .tmpl () method returns a jQuery collection of HTML elements that are added to the document by calling appendTo ('# movieListBag') .


Expressions


For substitution in the template of values ​​the tag $ {...} is used . Inside this tag, you can specify both the name of the property of the object passed to the .tmpl () method, and any valid JavaScript expression, including the function call.

Using object properties (array element):

 <h2> ${title} </h2> 

Using JavaScript Expressions:

 <p> : $${(budget / 1000000).toFixed(0)} .<br /> : $${(grossRevenue / 1000000).toFixed(1)} . </p> 


Template instance fields and methods


Inside expressions, you can access the current template instance via the $ item variable, and to refer to the current data item, the $ data variable.

Each template instance contains the following fields:
  1. data - contains a link to the data element associated with the template instance;
  2. tmpl - contains a link to the compiled template used for rendering;
  3. parent - if the template was called from another template using the {{tmpl}} tag, contains a link to the "parent" instance of the template;
  4. nodes - after rendering, contains links to HTML elements generated as a result of applying the template.

In addition, the .tmpl () method takes two arguments - data and options . You have already met the data argument, and a link to the data element is passed through it. And using the options argument, you can pass a reference to the object, all fields and methods of which will be transferred to each instance of the template created in the .tmpl () method.

The following is an example of using this parameter:

 <script id="movieTmpl" type="text/x-jquery-tmpl"> <div class="movie-bag"> <img src="Content/Thumbnails/${thumbnail}" class="thumbnail" /> <div class="base-info"> <h2> ${title} </h2> <p> : ${director}<br />  : ${actors}<br /> : ${year}<br /> : $${$item.formatBudget(budget)} .<br /> : $${$item.formatGrossRevenue(grossRevenue)} . </p> </div> </div> </script> 

 $(function () { $('#movieTmpl') .tmpl( dataItems, { formatBudget: function (value) { return (value / 1000000).toFixed(0); }, formatGrossRevenue: function (value) { return (value / 1000000).toFixed(1); } }) .appendTo('#movieListBag'); }); 

In this example, I use function calls for formatting budget values ​​and fees, but in order not to clutter up the global namespace, I passed them through the options parameter, after which these functions became available as methods of the current template instance.

And finally, an instance of the template contains the update () and html () methods, the use of which I will show below.

What does the compiled template look like?


You can see what a compiled template looks like by using the .template () method, which performs the compilation of templates. This method returns a function object whose contents are easy to see:

 $('#compiledTemplateBag').text('' + $('#movieTmpl').template()); 

The template used in the example above, after compilation is as follows (the text is formatted for better readability):

 function anonymous(jQuery, $item) { var $ = jQuery, call, _ = [], $data = $item.data; with ($data) { _.push('<div class="movie-bag"> <img src="Content/Thumbnails/'); if (typeof (thumbnail) !== 'undefined' && (thumbnail) != null) { _.push($.encode((typeof (thumbnail) === 'function' ? (thumbnail).call($item) : (thumbnail)))); } _.push('" class="thumbnail" /> <div class="base-info"> <h2> '); if (typeof (title) !== 'undefined' && (title) != null) { _.push($.encode((typeof (title) === 'function' ? (title).call($item) : (title)))); } _.push(' </h2> <p> : '); if (typeof (director) !== 'undefined' && (director) != null) { _.push($.encode((typeof (director) === 'function' ? (director).call($item) : (director)))); } _.push('<br />  : '); if (typeof (actors) !== 'undefined' && (actors) != null) { _.push($.encode((typeof (actors) === 'function' ? (actors).call($item) : (actors)))); } _.push('<br /> : '); if (typeof (year) !== 'undefined' && (year) != null) { _.push($.encode((typeof (year) === 'function' ? (year).call($item) : (year)))); } _.push(' </p> </div> </div>'); } return _; } 

I think that now it should be clear to you how the expressions specified in the $ {...} tag are processed - and this understanding can greatly help you when debugging! The fact is that jQuery Templates performs a relatively simple transformation of the template text, so if you make a mistake in an expression, the error message will relate to the text of the resulting function conversion and can often be extremely obscure.



Unfortunately, if the template is compiled with an error, then without special tweaks you will not be able to see the text of the function with an error, since the corresponding method is declared private.

Well, perhaps, this is the story about the work of jQuery Templates should be completed and proceed to its practical application.

Part two, practical


Conditions


In order to apply parts of the template depending on certain conditions, jQuery Templates uses {{if}} ... {{else}} ... {{/ if}} tags.

The following example shows the use of these tags (the complete example code is in the IfElseTag.htm file):

 <p> : {{if $item.data.media == 'dvd'}} <img src="Images/media-dvd.png" /> {{else $item.data.media == 'blue-ray'}} <img src="Images/media-blueray.png" /> {{else}} <img src="Images/media-unspecified.png" /> {{/if}} </p> 

As it is easy to guess, this code is designed to display the icon of the media on which the film is located. Here’s what it looks like in a browser:



As a condition in tags {{if}} and {{else}} you can use any valid JavaScript expression.

Collection processing


To handle collections in templates, the {{each}} ... {{/ /}} tag is used. The following example shows the use of the {{each}} tag to display a list of actors (the full example code is in the file EachTag1.htm ):

  : {{each actors}} ${$value} {{if $index < $data.actors.length - 1}} , {{/if}} {{/each}} 

In the browser, this example looks like this:



As an argument, the {{each}} tag can be passed an array, an object, or a jQuery collection. Inside, the {{each}} tag uses the jQuery.each () call, so everything that is said in the documentation about the jQuery.each () behavior also holds for the {{each}} tag. The example below demonstrates the use of the {{each}} tag to display all properties of an object (the full code for the example is in the file EachTag2.htm ):

 <script id="objTmpl" type="text/x-jquery-tmpl"> <div> <dl> {{each $data}} <dt> ${$index} </dt> <dd> ${$value} </dd> {{/each}} </dl> </div> </script> 

Inside the {{each}} tag, two variables are available: $ value , which contains a reference to the current element of the array, and $ index , which contains the index of the current element of the array or the name of the property.

Of course, you can use other tags inside the {{each}} tag, and besides, you will still have access to the $ item and $ data variables. In the above example, the variables $ index and $ data together with the {{if}} tag are used to display a comma between the names of the actors - unfortunately, the $ last variable is not provided, although it would be very useful!

Finally, if you suddenly have such a need, you can change the default variable names. In the example below, these names are changed to myIndex and myValue (the full code of the example is in the file EachTag3.htm ):

  : {{each(myIndex, myValue) actors}} ${myValue} {{if myIndex < $data.actors.length - 1}} , {{/if}} {{/each}} 

By the way, an attempt to change the name only for the $ index variable will not lead to anything good - there will be no error, but you will not be able to get access to the current value either!

Nested templates


Templates can be very large - and then it makes sense to divide them into several smaller parts or include duplicate parts, which are logical to highlight in a separate template. In jQuery Templates, this is done using nested templates, which are called using the {{tmpl}} tag.

The example below illustrates how to move part of the template code to another template (the full example code is in the NestedTemplates1.htm file):

 <script id="movieTmpl" type="text/x-jquery-tmpl"> ... <p> : ${director}<br />  : {{tmpl '#actorsTmpl'}}<br /> : ${year} </p> ... </script> <script id="actorsTmpl" type="text/x-jquery-tmpl"> {{each actors}} ${$value} {{if $index < $data.actors.length - 1}} , {{/if}} {{/each}} </script> 

The {{tmpl}} tag must contain the jQuery- selector of the template being called or the name of the template previously stored in the cache. Because in this example, the {{tmpl}} tag has no other arguments, the nested template will receive the same data element as the parent - but it will have its own template instance, and the parent field in it will refer to the parent template instance.

The following example demonstrates sending a new data element to a nested template and using a reference to the parent instance of the template. As in the case of using the .tmpl () method, if you specify an array when invoking a nested template, the template will be applied to each element of the array (the full code of the example is in the NestedTemplates2.htm file):

 <script id="movieTmpl" type="text/x-jquery-tmpl"> ... <p> : ${director}<br />  : {{tmpl(actors) '#actors_template'}}<br /> : ${year} </p> ... </script> <script id="actors_template" type="text/x-jquery-tmpl"> ${$data} {{if $data !== $item.parent.data.actors[$item.parent.data.actors.length - 1]}} , {{/if}} </script> 

And finally, the last example in this section shows how to pass the options argument to the nested template, and at the same time demonstrates how the options argument can be used to determine the last element in the array being processed (the full example code is in the NestedTemplates3.htm file):

 <script id="movieTmpl" type="text/x-jquery-tmpl"> ... <p> : ${director}<br />  : {{tmpl(actors, { last: actors[actors.length - 1] }) '#actors_template'}}<br /> : ${year} </p> ... </script> <script id="actors_template" type="text/x-jquery-tmpl"> ${$data} {{if $data !== $item.last}} , {{/if}} </script> 


Transformation


Another interesting feature of jQuery Templates is related to the transformation of HTML markup, for which the {{wrap}} tag is used (generally speaking, wrap is “wrapping”, but it seems to me that the term “transformation” reflects the essence of what is happening).

A classic example of using the {{wrap}} tag is creating bookmarks:



Here’s how it looks inside (the full code of the example is in the Transformation1.htm file):

 <script id="tabsContent" type="text/x-jquery-tmpl"> {{wrap(null, { viewState: $item.viewState }) '#tabsTmpl'}} <h1>English</h1> <div> <h2>The Ballad of East and West</h2> <h3>Rudyard Kipling</h3> <p>OH, East is East, and West is West...</p> </div> {{/wrap}} </script> 

The initial data for the transformation is placed in the tabContent template - it is this template that I will continue to instantiate.

The HTML markup that I will transform is placed in the {{wrap}} tag. For the {{wrap}} tag, exactly the same call notation is used as for the {[tmpl}} tag — i.e., you must specify the selector or the name of the template and you can additionally pass a reference to the data element and options. In this case, in the options parameter, I pass a link to the viewState object that contains the index of the selected bookmark.

The code for the transformation is as follows:

 <script id="tabsTmpl" type="text/x-jquery-tmpl"> <div class="tab-head"> {{each $item.html("h1", true)}} <div class="tab {{if $index == $item.viewState.index}}active{{/if}}"> ${$value} </div> {{/each}} </div> <div class="tab-body"> {{html $item.html("div")[$item.viewState.index]}} </div> </script> 

Here DIV.tab-head contains tabs for the tabs, and DIV.tab-body contains the contents of the selected bookmark.

Calling $ item.html ("h1", true)} fetches the data. The first parameter ( filter ) sets the filter for the first level elements , and the second parameter ( textOnly ) indicates that I want to get only the inner text of each selected element - i.e. in this case, I'll get a collection of strings, each of which will contain the text from the corresponding H1 tag. From this collection of lines, I create bookmark shortcuts.

I am a little upset by the fact that I cannot specify an arbitrary selector in the html () method - but, fortunately, no one bothers me to use any jQuery selectors on the results of this method.

Another funny moment is connected with the way the selector is set - when I try to set the selector in my favorite single quotes when I compile the template, an error occurs.

The next step I choose from the source data DIV , corresponding to the active tab, and put it in DIV.tab-body . Please note that in this case I use the {{html}} tag, and not $ {...} - the fact is that when using the $ {...} tag, special characters are escaped, but for me this is in this case not necessary.

Finally, I instantiate the template:

 var viewState = { index: 0 }; $('#tabsContent').tmpl(null, { viewState: viewState }).appendTo('#tabsBag'); 

And I install handlers for clicking on bookmarks:

 $('#tabsBag').delegate('.tab', 'click', function () { var item = $.tmplItem(this); item.viewState.index = $(this).index(); item.update(); }); 

What happens in the click handler? First, by calling $ .tmplItem (this), I get a link to the template instance associated with the current item. Then, I change the index of the selected bookmark - remember that we have in every instance of the template a reference to the viewState object? And in the final, I call the update () method of the template instance, which causes the template to be re-rendered, but with a different value in viewState .

The following example is more complex, but also more useful.

Its first difference from the previous example is that I dynamically create the initial data for the transformation (the full code of the example is in the file Transformation2.htm ):

 <script id="movieListTmpl" type="text/x-jquery-tmpl"> {{wrap(null, {viewState: $item.viewState}) '#tabsTmpl'}} {{tmpl(dataItems) '#movieTmpl'}} {{/wrap}} </script> <script id="movieTmpl" type="text/x-jquery-tmpl"> <div class="movie-bag"> <img src="Content/Thumbnails/${thumbnail}" class="thumbnail" /> ... </div> </script> 

 var viewState = { index: 0 }; $('#movieListTmpl').tmpl({ dataItems: dataItems }, { viewState: viewState }).appendTo('#tabsBag'); 

The second difference is because tags with the name of bookmarks are now not on the first level; when creating labels, I have to use jQuery selectors to get this information:

 <script id="tabsTmpl" type="text/x-jquery-tmpl"> <div class="tab-head"> {{each $item.html("div")}} <div class="tab {{if $index == $item.viewState.index}}active{{/if}}"> ${$('h2', $value).text()} </div> {{/each}} </div> <div class="tab-body"> {{html $item.html("div")[$item.viewState.index]}} </div> </script> 

In the browser, this example will look like this:



Pattern caching


Each call $ ('# ...'). Tmpl (...) compiles the template, which, despite the dramatically increased speed of JavaScript in modern browsers, can adversely affect performance. The developers of jQuery Templates could not get round this obvious fact with their attention, so jQuery Templates provides a mechanism for precompiling and caching templates.

Compiling and caching the template is as follows:

 $('#movieTmpl').template('movieTmpl'); 

The compiled template is stored in the jQuery Templates internal cache under the name movieTmpl . The jQuery.tmpl () method is used to access the cached template, and the first parameter is the name of the cached template:

 $.tmpl('movieTmpl', dataItems).appendTo('#movieListBag'); 

In the example below, you navigate through the movie list, and a cached template is used to display movie information.

The template code practically does not differ from those I used earlier, the only difference is that under the description of the film additional navigation links are placed (the full code of the example is in the CachedTemplates.htm file):

 <script id="movieTmpl" type="text/x-jquery-tmpl"> <div class="movie-bag"> <img src="Content/Thumbnails/${thumbnail}" class="thumbnail" /> <div class="base-info"> <h2> ${title} </h2> <p> : ${director}<br />  : ${actors}<br /> : ${year} </p> </div> </div> <div> {{if $item.canMoveBack}} <a href="javascript:" class="nav-link" x-inc="-1">[]</a> {{/if}} {{if $item.canMoveFwd}} <a href="javascript:" class="nav-link" x-inc="1">[]</a> {{/if}} </div> </script> 

The accompanying script is also simple:

 var movieIndex = 0; $(function () { $('#movieTmpl').template('movieTmpl'); updateMovie(); $('#movieBag').delegate('.nav-link', 'click', function () { movieIndex += parseInt($(this).attr('x-inc')); updateMovie(); }); }); function updateMovie() { $('#movieBag').empty(); $('#movieBag').append( $.tmpl('movieTmpl', dataItems[movieIndex], { canMoveBack: movieIndex > 0, canMoveFwd: movieIndex < dataItems.length - 1 })); } 

The clicker on the navigation link changes the index of the selected movie, and then calls the updateMovie () function, which first clears the container with the description of the movie, and then fills it with new data.

Here’s how this example looks in a browser:



Dynamic template loading


Unfortunately, the code shown below will not work:

 <script id="movieTmpl" src="Templates/DynamicLoading.htm" type="text/x-jquery-tmpl"></script> 

The browser, of course, will download the corresponding file - but you still will not be able to access its contents.

But the template can still be placed in a separate file, and this will require literally one additional line of code (the full code of the example is in the DynamicLoading.htm file ):

 $(function () { $.get('Templates/DynamicLoading.htm', {}, function (templateBody) { $.tmpl(templateBody, dataItems).appendTo('#movieListBag'); }); }); 

Becausein this case, we get a template in the form of text, to instantiate it, the jQuery.tmpl () method is used , the first argument to which the resulting template text is passed.

Yes, the jQuery.tmpl () method is used to instantiate both cached templates by name and templates specified as text (tradition! ..) - however, it is smart enough to distinguish them from each other.

If you need to load several related templates, you can use the WaitSync library (see “ Synchronizing Asynchronous Calls. WaitSync ”) or write your own synchronizer (the full code of the example is in the DynamicLoading2.htm file ):

 $(function () { var ws = new WaitSync(function () { $.tmpl('movieTmpl', dataItems).appendTo('#movieListBag'); }); $.ajax({ cache: false, url: 'Templates/MovieTmpl.htm', success: ws.wrap('MovieTmpl', function (templateBody) { $.template('movieTmpl', templateBody); }), error: ws.wrap('MovieTmpl', function () { alert('Error loading MovieTmpl.htm!'); }) }); $.ajax({ cache: false, url: 'Templates/ActorsTmpl.htm', success: ws.wrap('ActorsTmpl', function (templateBody) { $.template('actorsTmpl', templateBody); }), error: ws.wrap('ActorsTmpl', function () { alert('Error loading ActorsTmpl.htm!'); }) }); }); 

Note that in this case, the actorsTmpl template is called by name (file Templates \ MovieTmpl.htm ):

 <p> : ${director}<br />  : {{tmpl(actors, { last: actors[actors.length - 1] }) 'actorsTmpl'}}<br /> : ${year} </p> 


Dynamic update


In the last section of the practical part, I will show two more scenarios for jQuery Templates — changing the associated data and replacing the associated template.

In the example below, the ability to change its rating has been added for each movie (the full code of the example is in the DynamicUpdate1.htm file ):

 <script id="movieTmpl" type="text/x-jquery-tmpl"> <div class="movie-bag"> <img src="Content/Thumbnails/${thumbnail}" class="thumbnail" /> <div class="base-info"> ... <p> : <img src="Images/rating-down.png" alt="" title="-1" class="rating-button" x-inc="-1" /> ${rating} <img src="Images/rating-up.png" alt="" title="+1" class="rating-button" x-inc="1" /> </p> </div> </div> </script> 

Companion Code:

 $(function () { $('#movieTmpl').tmpl(dataItems).appendTo('#movieListBag'); $('#movieListBag').delegate('.rating-button', 'click', function () { var item = $.tmplItem(this); item.data.rating += parseInt($(this).attr('x-inc')); item.update(); }); }); 

As you can see, this code is very similar to the bookmarks code from the “Transformation” section, only when working with bookmarks, I accessed the viewState shared object , and here I work with data associated with an instance of the template.

In the browser, this example looks like this:



The following example demonstrates the substitution of the associated template (the full code of the example is in the file DynamicUpdate2.htm ):

 <script id="movieShortTmpl" type="text/x-jquery-tmpl"> <div class="movie-bag"> {{tmpl '#movieMainTmpl'}} <p style="clear: both"><a href="javascript:" class="more-details">[...]</a></p> </div> </script> <script id="movieFullTmpl" type="text/x-jquery-tmpl"> <div class="movie-bag"> {{tmpl '#movieMainTmpl'}} <p style="clear: both">  :</p> <div> {{each frames}} <img src="Content/Frames/${$value}" /> {{/each}} </div> <p><a href="javascript:" class="more-details">[...]</a></p> </div> </script> 

Here I use two templates, movieShortTmpl and movieFullTmpl , the common part of which is rendered into the movieMainTmpl template .

Companion Code:

 $(function () { var shortTemplate = $('#movieShortTmpl').template('shortTemplate'); var fullTemplate = $('#movieFullTmpl').template(); $.tmpl('shortTemplate', dataItems).appendTo('#movieListBag'); $('#movieListBag').delegate('.more-details', 'click', function () { var item = $.tmplItem(this); item.tmpl = item.tmpl === shortTemplate ? fullTemplate : shortTemplate; item.update(); }); }); 

I think this code requires additional explanations.

To replace the template, I need a link to the compiled template. I get these links using .template () calls . In addition, becauseThe shortTemplate template is used to render the movie list after the page loads, I save it in the cache so that I can instantiate it by name.

The code of the handler for clicking the “More / less” links is very similar to the code from the previous example, in it I assign a link to the tmpl field to one of the previously compiled templates and call the update () method for rendering.

In the browser, this example looks like this:



Conclusion


The code of examples used in the article can be downloaded from this link .

You can download jQuery Templates from the ASP.NET CDN website or directly from the GitHub repository:

Documentation for jQuery Templates is available on the jQuery documentation site .

In the examples, I used jQuery 1.5 RC1 , but jQuery Templates will work starting with jQuery 1.4.2 - in my last project, such a bundle was used.

The links below will help you learn more about jQuery Templates :

To get an idea of jQuery Templates performance compared to other “template engines”, take a look at the Brian Landau article Benchmarking Javascript Templating Libraries ”.

And in conclusion, I want to thank Vitaly Dilmukhametov and Denis Gladkikh for the valuable comments made in the process of working on the article.

Source: https://habr.com/ru/post/112843/


All Articles