Handlebars template engine for Play Framework
This module is created for using Handlebars templates with Play Framework. It uses Handlebars.java under the hood with an additional resolver for the play JSON objects. Both Scala and Java are supported.
Table of Contents
Install
-
Add the library in
built.sbt
Play 2.6, Scala 2.12
libraryDependencies += "com.github.andriykuba" % "play-handlebars" % "2.6.7"
Play 2.5, Scala 2.11
libraryDependencies += "com.github.andriykuba" % "play-handlebars" % "2.5.11"
-
Enable the module in
conf\application.conf
play.modules.enabled += "com.github.andriykuba.play.handlebars.HandlebarsModule"
-
Configure the templates folder and cache (optional)
handlebars{ directory = "/templates" #"/templates" by default extension = ".hbs" #".hbs" by default isCacheEnabled = true #true by default }
-
Configure
build.sbt
to take the templates folder in to the distribution package// Copy handlebars templates to the production import Path.relativeTo mappings in Universal ++= { val basePath = (baseDirectory.value).get.head ((baseDirectory.value / "templates" ** "*" get) pair relativeTo(basePath)) }
Usage
Java
Inject HandlebarsApi
into controller and call handlebarsApi.html(templateName, data)
method.
public class HomeController extends Controller {
@Inject
private HandlebarsApi handlebarsApi;
public Result index() {
// Data.
final Map<String, Object> data = new HashMap<>();
data.put("title", "Page Title");
data.put("header", "Header");
data.put("main", ImmutableMap.of("article", "Main Article"));
data.put("footer", "Footer");
// Fill it with the data.
final Content page = handlebarsApi.html("page", data, Context.current().lang().code());
// Return the page to the client.
return ok(page);
}
}
Scala
Inject HandlebarsApi
into controller with trait HandlebarsSupport
and call render(templateName, data)
method.
class HomeController @Inject() (val handlebarsApi: HandlebarsApi)extends Controller with HandlebarsSupport{
def index = Action { implicit request =>{
val jsonData =
Json.obj("users" -> Json.arr(
Json.obj(
"name" -> "Jhon",
"age" -> 4,
"role" -> "Worker"
),
Json.obj(
"name" -> "Duck",
"age" -> 6,
"role" -> "Administrator"
)))
val page = render("page", jsonData)
Ok(page)
}}
}
In Scala version with Json data flash variables automatically added to the jsonData object.
Redirect(controllers.routes.HomeController.myForm()).flashing("success" -> "The document has been created")
Previous flash variable could be extracted in a template as
<div>{{flash.success}}</div>
Play helpers
Assets
assets
helper is the replacement for the twirl @routes.Assets.versioned
method.
<link rel="stylesheet" media="screen" href="{{asset "stylesheets/main.css"}}">
Resulting HTML:
<link rel="stylesheet" media="screen" href="/assets/stylesheets/d41d8cd98f00b204e9800998ecf8427e-main.css">
Do not forget to configure versioning in the build file pipelineStages := Seq(digest)
for the production and pipelineStages in Assets := Seq(digest)
for the development.
Reverse routing
route
helper is the replacement for the twirl reverse routing "<full-package-name>.routes.<controller>.<action>"
<form action="{{route "controllers.SecureController.loginSubmit"}}" method="POST">
Resulting HTML:
<form action="\login" method="POST">
route
helper also works with the String, Integer or variable:
{{route "controllers.UserController.user(\"admin\")"}}
{{route "controllers.UserListController.page(42)"}}
{{route "controllers.FriendsController.friends(user.name)"}}
Message
message
helper is the replacement for the twirl @Message(key)
method. It also could take arguments like the original method.
<div>{{message "page.header.sub" "name"}}</div>
In the messages.en
file
page.header.sub=Page Sub Header {0}
Resulting HTML:
<div>Page Sub Header name</div>
i18n
messages
helper use the language that was passed to the render
or html
method as a language code string. This code combine in to the handlebars
context as a language
variable, so it can be used in template.
<html lang="{{language}}">
In scala
the HandlebarsSupport
trait takes the language code from the implicit Lang
variable. The implicit request2lang
method of the Play Framework Controller
class convert RequestHeader
to the Lang
. So, if you need the i18n support in the applications, you need to call your code with the implicit request
. The example:
def index = Action { implicit request =>{
// Your code, like render("page", jsonData), or any other that use Lang object
}}
String helpers
Encode url parameter
encodeUrlParameter
encode the string that it could be used as URL parameter. It use java.net.URLEncoder.encode
under the hood.
<a href="https://www.google.com?q={{encodeUrlParameter "blue+light blue"}}">search</a>
Resulting HTML:
<a href="https://www.google.com?q=blue%2Blight+blue">search</a>
If equals
if_equals
compare two objects and return the value if they are equal.
<ul>
{{#each vote.options}}
<li><input type="radio" name="vote" value="{{@key}}" {{if_equals @key user.vote "checked"}}>{{this}}</li>
{{/each}}
</ul>
Resulting HTML:
<ul>
<li><input type="radio" name="vote" value="one">first</li>
<li><input type="radio" name="vote" value="second" checked>second</li>
<li><input type="radio" name="vote" value="third">third</li>
</ul>
Concat
concat
concatenate the string representation of the parameters in one string.
<div>{{concat "static" variable}}
Resulting HTML:
<div>static and some dynamic</div>
It useful to use in subexpressions
<div>{{message (concat 'category.name.' category)}}</div>
Scala Json Value Resolver
It works similar to JsonNodeValueResolver
but resolve the classes from the play.api.libs.json
package