Play specific tag. Lookup message string.
@msg("validation.required")
The above has the same effect of the following groovy template code:
&('validation.required')
You can also pass parameters:
@msg("some.message", "param1")
You can pass variable as message (Start from v1.0.0-20120718):
@{String message = "validation.required"}
@msg(message)
Play specific tag. Reverse lookup URL.
@url(Application.index)
The above code is equal to the following groovy template code:
@{Applicaiton.index}
You can also reverse lookup static url
@url(/public/javascripts/myscript.js)
Play specific tag. Absolute reverse lookup URL.
@fullUrl(Applicaiton.index)
The above code is equal to the following groovy template code:
@@{Application.index}
Assign the enclosed block into a variable.
@assign("roleSelector") {
<select>
@for(Role role: Role.findAll()){
<option value="@role.getId()">role.toString()</option>
}
</select>
}
...
<label>select role</label>
@roleSelector.raw()
The variable name specified in @assign
must be unique across the context where @assign
is put in. Otherwise you will expect a compilation exception
To assign to a final variable pass the second parameter true
:
@assign("roleSelector", true) {
<select>
@for(Role role: Role.findAll()){
<option value="@role.getId()">role.toString()</option>
}
</select>
}
The benefit of final variable is that you can use it directly inside @for
loop.
The args
tag declare variables used in the template.
@args String var1, int var2, ...
or declare render arguments in multiple lines (start from 1.0.0-RC7):
@args {
String var1, int var2
boolean var3
...
}
args
is one of few tags that are not invoked in tag(...) style. At the moment please use ";" to terminate @args
statement. This limitation will be removed in the future, and line-break could be an natural way to terminate the statement
You can have any arbitrary number of args
statement in any where of your template, all variables declared will be effective in your template.
PlayRythm specific tag. This is a clone of the authenticityToken tag in Play’s groovy template.
@authenticityToken()
Rendered as:
<input type="hidden" name="authenticityToken"
value="1c6d92fed96200347f06b7c5e1a3a28fa258ef7c">
PlayRythm specific tag. Use authenticityTokenValue
when you want to put the authenticity token value inside a javascript code in your view:
$.post("@url(User.save())",
{authenticityToken: '@authenticityTokenValue()', ...},
function(data){...});
Rendered as:
$.post("/user/save",
{authenticityToken: "1c6d92fed96200347f06b7c5e1a3a28fa258ef7c", ...},
function(data){...});
Break @for
loop
@for(User user: users) {
@if(theUserId.equals(user.getId())) {
@break
}
}
Caches the tag body or use cached tag body
@cache("5min") {
<p>This content will be cached for 5 minutes</p>
including calling to any tags like:
@myTag()
}
Parameters:
- empty parameter: the enclosed content get cached for duration defined in “rythm.cache.defaultTTL” seconds.By default it’s one hour
- first parameter: optional. specify the cache duration. Examples:
- “5min”, five minutes
- “1h”: one hour
- “10s”: ten seconds
- “360d”: three hundred and sixty days
- “forever”: a fairly large time that could be considered forever in the current computing context
- 60 * 60: one hour
- rest parameters: optional. specify the variables used in the cache key generation. By default cache key is calculated literally using the enclosed content. However if rest parameters presented the cached key will be calculated using the parameters as well. For example
@cache(null, new Random().nextInt()) {
<p>[@(new Date().getTime())]this content will literally looks like not cached at all because the cache key changes every time</p>
}
Be cautious when you use @cache()
with template blocks contains dynamic content or nested dynamic content via @include()
or tag invocation. Cache key is calculated literally based on the content at parsing time, while dynamic content might changes at runtime. The rule of thumb is: if content or nested content via tag invocation or include
varies dynamically, do not cache it, or you cache it and pass all variables used across the content and nested content via tag invocation and include
directive
The cache decoration to tag invocation is safer than the @cache()
directive, because “cache decoration” will check parameter value at runtime when generating cache key:
@myTag(someVariable).cache("1h") // safer cache, cache key will vary if someVariable value changes
@cache("1h"){ // even someVariable value changed, the cache key will be the same so the output will remain unchanged
@myTag(someVariable)
}
h3. cacheOnProd
Same as “cache”, but cache happens only when play.Play.mode
is “prod
”.
cacheOnProd
is no longer available in v1.0. Use cache instead. However
you can configure rythm not to cache in dev mode by using @rythm.cache.prodOnly
setting.
By default rythm.cache.prodOnly
is set to true
so cache is not enabled at dev mode
Chain the following decoration functions together:
In the example of assign, you found that it always needs to call raw()
when you want to use the variable get assigned, by using chain
you can do it at one time:
@chain.raw().assign("roleSelector") {
<select>
@for(Role role: Role.findAll()){
<option value="@role.getId()">role.toString()</option>
}
</select>
}
...
<label>select role</label>
@roleSelector @// no longer need raw() extension any more
And you even add cache()
into the chain:
@chain.raw().assign("roleSelector").cache() {
...
}
The order of the chained function doesn’t matter as they are orthogonal concerns.
Mark a block of template to be output in compact mode without regarding to the global compact setting.
@compact() {
All content here will be output
in compact mode.
}
The above code will output the following content:
All content here will be output in compact mode
See also nocompact.
Continue current loop:
@for (User user: users) {
@if (user.isAdmin()) {
@continue
}
...
}
AKA @tag
, define an inline tag (helper in Razor, macro in velocity and freemarker) which can be invoked from within the same template, the parent template or children templates
@def sayHi(String who) {
Hi @who
}
To use the tag defined just follow the common way:
@sayHi("Play!framework")
or pass argument by name:
@sayHi(who: "Play!framework")
Inline tag must be defined before the invocation code. Otherwise you might get compilation error.
Define return type of inline tag:
@def boolean isMobile() {
@{
UserAgent ua = getRenderArg("userAgent");
return ua.isMobile();
}
}
And later on it can be used as:
@if (isMobile()) {
@mobileTag()
} else {
@pcTag()
}
See “defining inline tag” in the user guide
Used with template inheritance, this tag inserts the evaluated sub-template’s contents.
<!-- common header here -->
<div id="content">
@doLayout()
</div>
<!-- common footer here -->
doLayout
tag is an alias of render tag
An easier and clean way to @doLayout()
is @render()
See also template inheritance
An alias of renderBody
PlayRythm specific tag. Outputs the validation error message, if present, for the field specified by the tag parameter.
@error("user.name")
You can use the optional parameter to use a different field’s error message. This is useful when you want several fields to share a common error message.
@error("contact.street", "contact.address")
@error("contact.city", "contact.address")
@error("contact.country", "contact.address")
PlayRythm specific tag. Outputs the text hasError
if there is a validation error for the field specified by the tag parameter. This is useful for setting a CSS class for input fields with errors:
<input name="name" class="@errorClass("name")">
which is equivalent to:
<input name="name" class="@(play.data.validation.Validation.hasError("name") ? "hasError" : '')">
Alias of errors
. See below.
Corresponding to Groovy template’s errors. Iterates over the current validation errors.
<ul>
@errors() {
<li>@error</li>
}
The @error
tag defines implicit variables in its body.
error
, the errorerror_index
, the error’s index, starting at 1error_isLast
, true for the last elementerror_isFirst
, true for the first elementerror_parity
, alternates betweenodd
andeven
<table>
<tr><th>#</th><th>Error</th></tr>
@errors() {
<tr class="@error_parity"><td>@error_index</td><td>@error</td></tr>
}
</table>
You can also use the optional field parameter, or just the default parameter, to filter only the errors belonging to a certain field.
<ul>
@errors("myField") {
There where errors with the field myField<br />
<li>@error</li>
}
</ul>
Mark a block of template code default escape scheme:
@escape("JS"){
alert("Hello Rythm");
}
The above code set the default escape to JavaScript
. The parameter passed to @escape() could be one of the following:
- RAW – do not escape. Same effect with
@raw()
- CSV – escape as csv format
- HTML – escape as html format
- JS | JavaScript – escape as JavaScript format
- JAVA – escape as Java format
- XML – escape as XML format
Note
- the parameter is case insensitive.
- if no parameter is passed, then it default to HTML
- you pass the parameter within quotation mark or not
@exec("macro1")
See also Define and execute Macro
@expand("macro1")
See also Define and execute Macro
Makes the template inherit another template.
@extends(main)
or
@extends("main")
You can pass parameter to extended template if the there are arguments declared.
Suppose you have a parent template defined as:
@args String style;
<div class="panel @style">
@doLayout()
</div>
And in your extending template, you pass the argument style as:
@extends(panel, style: "span4")
or pass by position:
@extends(panel, "span4")
You can use debug
tag to output debug message to your log file or screen:
@debug("this is a debug message for %s", myvar)
Use for
to iterate a collection of objects. The syntax is the same as for loop in Java language:
<ul>
@for (Product product: products) {
<li>@product</li>
} else {
<div class="alert">No product found</div>
}
</ul>
The else
branch syntax is an new feature starting from v1.0.0-20121126 version.
The @for
tag defines implicit variables in it’s body. The variable names are prefixed with loop variable name:
name_index
, the item’s index, start with 1name_isFirst
, true for the first elementname_isLast
, true for the last elementname_parity
, alternates betweenodd
andeven
name_isOdd
, true if the current element is odd in sequencename_size
, the size of the collectionname_sep
, “,” if the current loop is not at the last item-
name__sep
, loop variable + “,” if the current loop is not at the last item name_utils
, the loop utils object-
name__utils
, loop variable + the loop utils object
<ul>
@for (Product product: products) {
<li class="@product_parity">@product_index. @product</li>
@product_sep
}
</ul>
If you need a special item separator other than the default xx_sep
, you can use xx_utils
object:
@for(String s: strList) {
@s_utils.sep(",")
@s_utils.preSep(",")
@s_utils.postSep(",")
}
in the above example, @s_utils.sep(",")
is the same as @s_sep
and @s_utils.postSep(",")
, which output a comma if the current loop is NOT at the last item. @s_utils.preSep(",")
output a comma if the current loop is not at the first item. This feature is very helpful when you want to print a list of items separated by a certain separator.
If you refer to a local variable inside the loop, you need to make sure they are declared as final
:
@{
String foo = "foo";
final String bar = foo;
}
@for(MyModel model: myModels) {
<p>@bar</p> @// this is okay
<p>@foo</p> @// this line will cause compilation error
...
}
You can also use the second form of @for
tag:
@for(int i = 0; i < 6; ++i) {
<li>the current index is @i</li>
}
You don’t have access to loop variables if you use the second @for
loop form. Neither can you use else
branch along with this second for loop style
Start from v1.0-b4, play-rythm support loop variable type inference. For example:
@args List<User> users
...
@for(user: users) {
...
}
In the above case, as you have declared users
as List<User>
type, you don’t need to declare the type of for loop variable user
, Rythm will automatically give type User
to it. Type inference also support type inference for Map
iterables:
@args Map<String, Integer> myMap
...
@for(key: myMap.keySet()) {...} @// key type is String
@for(val: myMap.values()) {...} @// val type is Integer
Limitation of type inference:
- The iterable must be declared with
@args
statement - The iterable cannot be an expression, e.g.
@for(v: foo.bar()){...}
In the above case when Rythm cannot identify the loop variable type, java.lang.Object
will be used as the type of the loop variable
Since v1.0-b4 Play-rythm support new loop styles:
@for(s : list) {...}
@for(s in list) {...}
@for(s <- list) {...}
Since v1.0-b4 Play-rythm support new loop iterable expressions include String separator and Number range:
@for("a, b, c"){@__sep} @// output: a,b,c
@for("a : b:c"){@__sep} @// output: a,b,c
@for("a; b;c"){@__sep} @// output: a,b,c
@for("a - b - c"){@__sep} @// output: a,b,c
@for("a_b_c"){@__sep} @// output: a,b,c
Separator priority: ; > , > : > _ > -. E.g. “foo;bar,c:d” are separated into two groups: “foo” and “bar,c:d”
@for (1 .. 5) {@_} @// output: 1,2,3,4
@for ([1 .. 5]) {@_} @// output: 1,2,3,4,5
Since v1.0-b4 Play-rythm support new loop separators:
@for("a:b:c"){@__sep} @// new style output a,b,c
@for("a:b:c"){@(_)@_sep} @// old style output a,b,c
@for(s in "a:b:c"){@s__sep} @// new style output a,b,c
@for(s in "a:b:c"){@(s)@s_sep} @// old style output a,b,c
@for("a:b:c"){@__utils.sep("|")} @// new style output a|b|c
@for("a:b:c"){@(_)@_utils.sep("|")} @// old style output a|b|c
Retrieves value defined with a set tag. You may use the get/set mechanism to exchange values between templates, layouts and sub-templates.
<head>
<title>@get("title")</title>
</head>
You can provide a default value in the following way, which will display “Homepage”, if title has not been specified:
<head>
<title>@get("title": "Homepage")</title>
</head>
Evaluates a given test, and if true, evaluate the tag body. The syntax is the same as if
clause in Java language
@if ("en".equals(user.countryCode)) {
Connect user is @user
}
You can also use else
clause:
@if (null != user) {
Connected user is @user
} else {
Please log in
}
or else if
clause
@if (tasks.size() > 1) {
Busy tasklist
} else if (tasks.size() > 0) {
One task in the list
} else {
Nothing to do
}
Import package or class.
@import java.awt.*, java.io.*,...
or declare import statements in multiple lines (start from 1.0.0-RC7):
@import {
java.awt.*, java.io.*
static java.lang.Math.*
...
}
Do an inline include
a template into the current template:
@include("common.utils")
See Include other templates section for details
Enable dynamic tag invocation:
@invoke("designer." + platform).ignoreNonExistsTag()
See Dynamic tag invocation section for details4
@jsAction()
is a play specific tag that returns a JavaScript function which constructs a URL based on a server action and free variables. It does not perform an AJAX request; these have to be done by hand using the returned URL.
Let’s see an example:
GET /users/{id} Users.show
Now you can import this route client side:
<script type="text/javascript">
@assign("showUserUrl"){@url(Users.show(":id"))}
var showUserAction = @jsAction(showUserUrl)
var displayUserDetail = function(userId) {
$('userDetail').load( showUserAction({id: userId}) )
}
</script>
Note at the moment @jsAction()
tag in PlayRythm is no as convenient to use as the groovy #{jsAction /}
tag that you must use a special @assign
statement to get the url reverse lookup result before passing it to the @jsAction()
tag:
@assign("showUserUrl"){@url(Users.show(":id"))}
var showUserAction = @jsAction(showUserUrl)
It’s desired the syntax could be simplified as:
var showUserAction = @jsAction(Users.show(":id")) @// note this has NOT been implemented yet!
Define a template macro.
@macro() {
macro content
}
See also @exec
and Define and execute Macro
Mark a block of template to be output NOT in compact mode without regarding to the global compact setting.
@nocompact() {
All content here will be output
in nocompact mode.
}
The above code will output the following content:
All content here will be output
in compact mode
See also compact.
AKA doBody
, renderBody
is an alias of doLayout. is used to render the tag body.
@renderBody()
If tag body is supplied along with callback
extension, then you can pass parameters into renderBody
call:
@renderBody(user.role)
or by name:
@renderBody(role: user.role)
AKA renderSection
and doLayout
, used with template inheritance, this tag inserts the evaluated sub-template’s contents defined with section
tag
<div id="sidebar">
@render("sidebar")
</div>
When no section name specified this tag output the layout content:
@render() @// also @doLayout(), same effect as groovy's #{doLayout/}
Start from v1.0.0 Rythm support define default content for section:
<div id="footer">
@renderSection("footer") {
@// here we define default content for footer section
@// if sub template failed to supply this section then
@// the default content will be output instead
<p>Site footer - © Santa Clause</p>
}
</div>
Abort the template execution and return to caller:
@if(!user.isAdmin()) {
@return
}
<p class="admin-panel">...
Define a block of template to be output in parent template’s named section.
@section("sidebar") {
<ul>
<li><a href="#">Link one</li>
<li><a href="#">Link two</li>
</ul>
}
Define a value which can be retrieved in the same template or any layout with the get tag.
@set(title: "Admin")
@set(style: "span6")
You can use any expression in set
tag
@set(title:"Profile of " + user.login)
Unlike set tag in Groovy template engine, Rythm set
tag does not accept tag body. You can use section tag to achieve the same result.
Analog of the spaceless tag from Django. Removes whitespace (\s
) characters between HTML tags, including tabs and newlines.
Template:
@spaceless() {
<ul>
<li>First item</li>
<li>Second item</li>
</ul>
}
Output:
<ul><li>First item</li><li>Second item</li></ul>
Alias of @def()
@tag
is not used to invoke a tag. Check the user guide to see how to invoke a tag.
Call the current template itself as a tag
@args int max, int i, int j
@i @if (j < max) {
@{
int t = i;
i = j;
j = i + t;
}
, @this(max, i, j) @// recursively call to this template
} else {
<hr/>
<h3>Fibonacci tag template source</h3>
<pre>
@(getTemplateClass(false).getTemplateSource())
</pre>
<h3>Fibonacci tag java source</h3>
<pre>
@(getTemplateClass(false).javaSource)
</pre>
}
Mark a block of template code that by default output raw data for expression:
@{
String title = "<h1>title</h1>";
String body = "<p>some news</p";
}
@raw() {
@title
@body
}
The above code has the same effect as below
@{
String title = "<h1>title</h1>";
String body = "<p>some news</p>";
}
@title.raw()
@body.raw()
Output timestamp in place
now is @ts() @// produce somethign like "now is 134325875435"
Define a block of code that not to be parsed by Rythm.
@verbatim() {
OK, anything inside this block is not parsed: @someTag, @someExpression, etc
}
Mark the current template as a simple template. A simple template is slightly faster than normal template and has the following constraint:
- Doesn’t have implicit imports
- Doesn’t have implicit objects
- Cannot extends other templates
PlayRythm provides all default configuration settings that cater for most common use cases.
configuration | description | default value |
---|---|---|
rythm.mode |
set rythm template engine to run in dev or prod mode | the value of play.mode |
rythm.compactOutput |
remove redundant space and line breaks | true in prod mode and false in dev mode |
rythm.enableJavaExtensions |
enable Java extension parsing | true |