Handlebars.java

Logic-less and semantic templates with Java


by Edgar Espina Theme by mattgraham

Helpers in Handlebars.java

In this section you will learn about helpers, their syntax, how to register and lot more.

Helpers are a key concept of Handlebars.java. Through ahelperyou can add custom logic from a safe and controlled way. Helpers are lightweight components that can be tested using tools like JUnit

There are two types of helpers:

Basic helpers:
{{name context? [argument]* [hash]*}}
Block helpers:
{{#name context? [argument]* [hash]*}}
...
{{/name}}
Name, context, argument, and hash are defined as follows:
name: qid;

context: expression;

argument: expression;

hash: id '=' expression;

expression: literal | qid;

qid
  :
     '../' qid
  |  id '[' .* ']' ('.' | '/') qid
  |  id '[' .* ']' qid
  |  id ('.' | '/') qid
  |  'id'
  ;

id: idStart (idStart | idPart)*;

idStart: [a-zA-Z_$@];

idPart: [0-9];

literal
  :
    stringLiteral
  | boolLiteral
  | numberLiteral
  | 'this'
  | '.'
  ;

stringLiteral:'"' .* '"';

boolLiteral:'true' | 'false';

numberLiteral: '0'..'9'+;

Registering custom helpers

There are two way of registering helpers in Handlebars.java:

Helper options

Now you know how to register a helper, let's see what you can do with it.

Parameters

Accessing to the parameterarg0using thehelperinterface:
{{blog this "arg0"}}
...
public CharSequence apply(Blog blog, Options options) {
  return options.param(0);
}
Accessing to the parameterarg0using ahelpermethod:
{{blog this "arg0"}}
...
public CharSequence blog(Blog blog, String arg0) {
  return arg0;
}
Auto-boxing of parameters using theoptionsvariable:
{{blog this "string" true 678}}
...
public CharSequence blog(Blog blog, Options options) {
  String str = options.param(0);
  boolean bool = options.param(1);
  int num = options.param(2);
}
Type safe parameters using ahelpermethod:
{{blog this "string" true 678}}
...
public CharSequence blog(Blog blog, String str, boolean bool, int num) {
}
Setting a default value to an optional parameter:
{{blog this}}
...
public CharSequence blog(Blog blog, Options options) {
  return options.param(0, "arg0");
}
Accessing to a context stack value:
{{blog this author}}
...
public CharSequence blog(Blog blog, Author author) {
  return author.getName();
}

In the example above,authoris a value in the context stack. Ifauthor isn't found anullvalue will be injected in theauthorvariable.

SettingstringParams: truelet you access to the parameter name when a context stack value isn't resolved:
handlebars.setStringParams(true);
...
{{blog this edgar}}
...
public CharSequence blog(Blog blog, Object author) {
  return author instanceof String? author: author.getName();
}

Hash Parameters

Accessing to the hash parameternameusing thehelperinterface:
{{blog this name="Blog"}}
...
public CharSequence apply(Blog blog, Options options) {
  return options.hash("name");
}
Auto-boxing of hash parameter using theoptionsvariable:
{{blog this s="string" b=true n=678}}
...
public CharSequence blog(Blog blog, Options options) {
  String str = options.hash("s");
  boolean bool = options.get("b");
  int num = options.get("n");
}
Setting a default value to an optional hash parameter:
{{blog this}}
...
public CharSequence blog(Blog blog, Options options) {
  return options.hash("arg0", "default value");
}

Helper return value

A helper method must return an instance of ajava.lang.CharSequenceornull. For none null results, the value is HTML escaped.

You can unescape the HTML code in one of three ways:

  1. Using {{& }}
    {{&blog this}}
    
  2. Using {{{ }}}
    {{{blog this}}}
    
  3. Using Handlebars.SafeString
    public CharSequence blog(Blog blog, Options options) {
      return new Handlebars.SafeString("<div>Hello</div>");
    }
    ...
    {{blog this}}
    

From the three methods: Handlebars.SafeString is 100% safe, bc doesn't depends on how you invoke the helper.

Helper missing

If a helper isn't found ajava.lang.IllegalArgumentExceptionoccurs. You can change this by registering ahelperMissinghelper.

OverridehelperMissingand return the template block (if any).
  handlebars.registerHelper(Handlebars.HELPER_MISSING, new Helper<Object>() {
    @Override
    public CharSequence apply(final Object context, final Options options)
      throws IOException {
      return options.fn.text();
    }
  });

Conclusion

It is great if you can keep the inherited logic-less from Mustache. This is what will make your application easy to understand, change and evolve.

At the same time logic-less is hard to keep for medium/large size applications or probably you don't own the code and changing the model isn't an option.

In those cases Handlebars.java is here to help you. It wont let you add logic in the HTML but you can add as much logic as you need through helpers.

Want to contribute?

Thank you, for reading the Handlebars.java blog.