📜 ⬆️ ⬇️

Handlebars. Guide to action

This article contains a description of the main features of the Handlebars template engine and is a free translation of its official documentation. So let's go ...



With Handlebars, you can build effective semantic patterns. Handlebars templates are in many ways compatible with Mustache templates - in most cases they are interchangeable. Full details can be found at this link .

Expressions


To get started with Handlebars, you need to include the file handlebars.js :
')
<script src="js/handlebars.js"></script> 

Handlebars templates look like plain HTML, with embedded handlebars expressions.

The simplest handlebars expression is a simple identifier:

 {{some_contents}} 

The identifier can be any Unicode character except for the following:

  ! " # % & ' ( ) * + , . / ; < = > @ [ \ ] ^ ` { | } ~ 

You can insert the Handlebars template into your HTML code by including it in the <script /> tag:

 <script id="entry-template" type="text/x-handlebars-template"> <div class="entry"> <h1>{{title}}</h1> </div> </script> 

In JavaScript, a template is compiled using Handlebars.compile:

 var source = $("#entry-template").html(); var template = Handlebars.compile(source); 

It is also possible to pre-compile the template , which will lead to less resource intensity, which can be very important when working with mobile devices.

Handlebars templates are evaluated depending on the context passed to the compiled method. By completing our template with the following content:

 var context = { title: " " }; var html = template(context); 

We will get the HTML code:

 <div class="entry"> <h1> </h1> </div> 

Handlebars can have paths separated by dots. They allow you to search for properties nested below the current context:

 <div class="entry"> <h1>{{title}}</h1> <h2>{{author.name}}</h2> </div> 

When the template runs, the author property is taken from the current context, then the name property is taken from the result.

This template will work with the following context:

 var context = { title: " ", author: { id: 47, name: " " } }; 

Handlebars paths can also include ../ segments that allow you to specify a path relative to the parent context. We will face them when we consider block helpers.

Handlebars escapes expressions placed in double brackets {{}}. To avoid this, you need to put the expression in the triple brackets {{{}}}. So that in the future, when writing the HTML-generating helper code, to avoid screening the result returned by it, we will return new Handlebars.SafeString (result)

Helpers


Handlebars helper is a simple identifier, followed by zero or more parameters (separated by spaces). Each parameter is a handlebars expression. The helper parameter can also be a simple string, number, or boolean value. The helper performs certain operations with parameters and returns HTML code.

 {{{link "..." poem.url}}} 

Handlebars helpers can be available in a template from any context.

 <div> <h1>{{poem.title}}</h1> {{link "..." poem.url}} </div> 

You can register a helper using the Handlebars.registerHelper method. When using the following context and helper:

 var context = { poem: { title: " ", url: "Sobake_Kachalova.html" } }; Handlebars.registerHelper('link', function(text, url) { url = Handlebars.escapeExpression(url); //  text = Handlebars.escapeExpression(text); return new Handlebars.SafeString("<a href='" + url + "'>" + text + "</a>"); }); 

We get the following result:

 <div> <h1> </h1> <a href='Sobake_Kachalova.html'>...</a> </div> 

Handlebars helpers can also pass a sequence of key-value pairs after all unmatched parameters. Keys should be simple identifiers, and values ​​should be handlebars-expressions (i.e. values ​​can be identifiers, paths, or strings).

 {{link "..." href=poem.url class="poem"}} 

Registration helper:

 Handlebars.registerHelper('link', function(text, options) { console.log(options.hash['href']); //,   poem.url console.log(options.hash['class']); //"poem" return new Handlebars.SafeString("<a href=\"" + options.hash['href'] + "\">" + Handlebars.escapeExpression(text) + "</a>"); }); 

There can potentially be a name conflict between helpers and data fields (for example, in our context, the {{name}} handlebars expression and {{name}} helper are used). Handlebars offers us the following opportunity to resolve this conflict:

 <p>{{./name}} or {{this/name}} or {{this.name}}</p> 

Any of the above handlebars expressions will call the {{name}} data field in the current context, not the helper with the same name.

Block helpers


Block helpers allow you to define custom iterators, as well as other functionality with which you can call the passed block in a new context. Block helper is written as follows:
 {{#helper_name}}some_block{{/helper_name}} 

When registering a helper, the parameters in Handlebars.registerHelper are passed in the order in which they were passed to the helper by the user. Following all the parameters specified by the user, the options parameter follows. It has the following properties:

1) options.fn - contains a function that behaves like a normal compiled Handlebars template. As a parameter, the function takes a context and returns a string.

Example 1. Let's define a block helper that changes the markup of the text wrapped in it:

 <div class="body"> {{#bold}}{{body}}{{/bold}} </div> 

Check in:

 Handlebars.registerHelper('bold', function(options) { return '<div class="mybold">' + options.fn(this) + '</div>'; }); 

Since the content of a block helper is escaped when options.fn (context) is called, Handlebars does not escape the result returned by the block helper. If this is done, the internal content will be screened twice!

Here, as a parameter of the function, we passed the current context (this). Let's specify another context by passing it to the helper as a parameter:

Example 2

 <div class="entry"> {{author}} {{#with poem}} <div class="title">{{title}}</div> <div class="author">{{../author}}</div> <div class="year">{{year}}</div> {{/with}} </div> 

We could run this template with the following JSON having the title and year keys nested in the poem object:

 { author: " ", poem: { title: " ", year: 1925 } } 

Check in:

 Handlebars.registerHelper('with', function(context, options) { console.log(context); //{title: " ", year: 1925} return options.fn(context); }); 

We will get the HTML code:

 <div class="entry">   <div class="title"> </div> <div class="author"> </div> <div class="year">1925</div> </div> 

Note that in this example we used the ../ segment to indicate the path to the author property, which is outside the context of poem.

Example 3. Let's write an iterator that creates a <ul /> wrapper and inserts each block passed to it as an <li /> element.

 {{#list nav}} <a href="{{url}}">{{title}}</a> {{/list}} 

We could run this template using the following context:

 { nav: [ { url: "http://www.museum-esenin.ru/biography", title: "  " }, { url: "http://www.fedordostoevsky.ru/biography", title: " . . " }, ] } 

Registration helper:

 Handlebars.registerHelper('list', function(context, options) { var ret = "<ul>"; for(var i=0, j=context.length; i<j; i++) { ret = ret + "<li>" + options.fn(context[i]) + "</li>"; } return ret + "</ul>"; }); 

We will get the HTML code:

 <ul> <li><a href="http://www.museum-esenin.ru/biography">  </a></li> <li><a href="http://www.fedordostoevsky.ru/biography"> . . </a></li> </ul> 

2) options.inverse - the function is used when working with control structures of Handlebars. Control structures typically do not change the current context — instead, they decide whether to call the block based on the value of the passed parameter.

 {{#if isActive}} <img src="minus.gif" alt="Active"> {{else}} <img src="plus.gif" alt="Inactive"> {{/if}} 

Handlebars returns the block following {{else}} through the options.inverse function:

 Handlebars.registerHelper('if', function(conditional, options) { if(conditional) { return options.fn(this); } else { return options.inverse(this); } }); 

3) options.hash - contains a sequence of key-value pairs transmitted to the helper after all unpaired parameters.

Example. Let's go back to the list helper and make it possible to add any number of attributes of the <ul /> wrapper that we create.

 {{#list nav id="nav-bar" class="top"}} <a href="{{url}}">{{title}}</a> {{/list}} 

Handlebars pass paired options into options.hash , where they are stored as keys to the value of the object.

Registration helper:

 Handlebars.registerHelper('list', function(context, options) { var attrs = []; for (key in options.hash) { attrs.push(key + '="' + options.hash[key] + '"'); } return "<ul " + attrs.join(" ") + ">" + context.map(function(item) { return "<li>" + options.fn(item) + "</li>"; }).join("\n") + "</ul>"; }); 

We will get the HTML code:

 <ul class="top" id="nav-bar"> <li><a href="http://www.museum-esenin.ru/biography">  </a></li> <li><a href="http://www.fedordostoevsky.ru/biography"> . . </a></li> </ul> 

Hash arguments provide a powerful opportunity to pass many additional parameters to the block helper without the complications associated with the positions of the arguments.

Built-in helpers


1) if - use this helper to display a block by condition.

 <div class="entry"> {{#if author}} <h1>{{firstName}} {{lastName}}</h1> {{else}} <h1> </h1> {{/if}} </div> 

2) unless - use this helper as a reverse if helper. The block will be displayed if the expression returns a false value.

 <div class="entry"> {{#unless license}} <h3 class="warning">:     !</h3> {{/unless}} </div> 

3) each - use this helper to iterate through lists. Inside a block, you can use this to reference a list item.

 <ul class="writers_list"> {{#each writers}} <li>{{@index}}: {{this}}</li> {{else}} <li> </li> {{/each}} </ul> 

This template can be used in the following context:

 { writers: [ ". . ", ". . ", " " ] } 

As a result, we get:

 <ul class="writers_list"> <li>0: . . </li> <li>1: . . </li> <li>2:  </li> </ul> 

The block following the {{else}} section is displayed only when the list is empty.

4) with - use this helper to shift the context of the handlebars-template section.

 <div class="entry"> <h1>{{title}}</h1> {{#with author}} <h2>{{firstName}} {{lastName}}</h2> {{else}} <h2> </h2> {{/with}} </div> 

This template can be used in the following context:

 { title: " ", author: { firstName: "", lastName: "" } } 

5) log - allows you to log the state of the context during the execution of the template.

 {{log ": " lastName "; : " firstName}} 

It is delegated to Handlebars.logger.log , which can be redefined to perform custom logging.
More information about embedded helpers with examples can be found at this link .

Reuse of templates (Partials)


Partials allows you to reuse code by creating common templates. Partials are regular handlebars templates that can be directly invoked through other templates.

To use Partial, you must first register it through Handlebars.registerPartial :

 Handlebars.registerPartial('myPartial', '{{name}}') 

Partial can be precompiled — in this case, the precompiled template is passed as the second parameter.

Partial call:

 {{> myPartial }} 

Partial runs in the current context. It is also possible to execute Partial in a user context by passing the context when calling Partial:

 {{> myPartial myOtherContext }} 

More information about Partials can be obtained by clicking on this link .

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


All Articles