All Downloads are FREE. Search and download functionalities are using the official Maven repository.

templates.docs.templatingEngine.html Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
{#==========================================
Docs : "Templating Engine"
==========================================#}

Templating Engine

The Templating Engine (also called view engine, or template engine), is the component that you use to generate dynamic text content. It can be used for multiple purposes but its most frequent use is to generate HTML pages.

The default Templating Engine included with Spincast by default is Pebble.

Using the Templating Engine

To evaluate a template, you can inject the TemplatingEngine component anywhere you need it. But the preferred way to generate HTML pages is to use the sendTemplateXXX(...) methods on the response() add-on :

public void myRouteHandler(AppRequestContext context) {

    JsonObject model = context.response().getModel();
        
    // ... adds variables to the model
        
    // Renders the response model using a template
    // and sends the result as HTML
    context.response().sendTemplateHtml("/templates/myTemplate.html");
}

You can also evaluate a template without sending it as the response. The templating() add-on give you direct access to the Templating Engine. Here's an example where you manually evaluate a template to generate the content of an email :

public void myRouteHandler(AppRequestContext context) {

    User user = getUser();
    
    JsonObject params = context.json().create();
    params.set("user", user);
    
    String emailBody = context.templating().fromTemplate("/templates/email.html", params);
        
    // ... do something with the content
}

Note that, by default, the path to a template is a classpath path. To load a template from the file system instead, use false as the "isClasspathPath" parameter :

public void myRouteHandler(AppRequestContext context) {

    User user = getUser();
    
    JsonObject params = context.json().create();
    params.set("user", user);
    
    String emailBody = context.templating().fromTemplate("/templates/email.html", 
                                                         false, // From the file system!
                                                         params);
    
    // ... do something with the content
}

Finally you can evaluate an inline template :

{% verbatim %}

public void myRouteHandler(AppRequestContext context) {

    // We can use a standard Map<String, Object> instead
    // of a JsonObject for the parameters
    Map<String, Object> params = new HashMap<String, Object>();
    params.set("name", "Stromgol");

    // This will be evaluated to "Hi Stromgol!"
    String result = context.templating().evaluate("Hi {{name}}!", params);
    
    // ... do something with the result
}
{% endverbatim %}

Templates basics (using Pebble)

The syntax to use for your templates depends on the Templating Engine implementation. Here, we'll show some examples using the default Templating Engine, Pebble. Make sure you read the Pebble documentation if you want to learn more...

Using the response model

If you are using the default way to render an HTML page, suing the response().sendTemplateHtml(...) method, you can use the response model as a container for the parameters your template needs. The response model becomes the root of all available variables when your template is rendered. For example, your Route Handler may look like :

public void myRouteHandler(AppRequestContext context) {

    // Gets the response model
    JsonObject model = context.response().getModel();
  
    // Creates a "user" on adds it to the
    // response model
    JsonObject user = context.json().create();
    user.set("name", "Stromgol");
    model.set("user", user);

    // Renders a template and sends it as HTML
    context.response().sendTemplateHtml("/templates/myTemplate.html");
}

The template, located on the classpath (at "src/main/resources/templates/myTemplate.html" in a Maven project) may look like this :

{% verbatim %}

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>My application</title>
    </head>
    <body>
        <h1>Hello {{user.name}}!</h1> 
    </body>
</html>
{% endverbatim %}

Using JsonPaths

When accessing the variables in a template, you can use JsonPaths. Here are some examples : {% verbatim %}

  • {{user.name}} : The "name" attribute on the user object.
  • {{user.books[2].title}} : The "title" attribute of the third book of the user object.
  • {{user['some key']}} or {{user["some key"]}} : The "some key" attribute of the user object. Here brackets are required because of the space in the key.
{% endverbatim %}

Default templating variables

Spincast automatically provides some variables that can be used when rendering a template. Those variables will always be available to any template rendering (except if you are not in the scope of an HTTP request). Spincast adds those variables using a "before" Filter : addDefaultGlobalTemplateVariables(...)

The provided variables are :

  • "pathParams" : The parameters parsed from the path of the request. To be used like {% verbatim %}{{pathParams.myParam}}{% endverbatim %}.
  • "qsParams" : The parameters parsed from the queryString of the request. Note that a single queryString variable may contain more than one values. To access the first value, use something like : {% verbatim %}{{qsParams.myParam[0]}}{% endverbatim %}.
  • "cookies" : The current Cookies. To be used like {% verbatim %}{{cookies.myCookie.value}}{% endverbatim %}.
  • "requestScopedVars" : The request scoped variables added by the various Route Handlers. To be used like {% verbatim %}{{requestScopedVars.myVar}}{% endverbatim %}.
  • "langAbrv" : The abreviation of the current Locale to use. For example : "en".
  • "cacheBuster" : The current cache buster code.
  • "routeId" : The id of the current route (of its main Route Handler).
  • "fullUrl" : The full URL of the current request.
  • "isHttps" : Is the current URL secure (HTTPS)?
  • "alerts" : The Alert messages, if any. Those also include Flash messages (Spincast automatically converts Flash messages to Alert messages). They also contain Alert messages that you may have explictly added using the addAlert(...) method of the response() add-on. For example :

    public void myRouteHandler(AppRequestContext context) {
    
        context.response().addAlert(AlertLevel.ERROR, "Some message");
    }

Layout

If you are building a traditional website and use templates to render HTML, make sure you read the "Template Inheritance", "extends" and "include" sections of the Pebble documentation to learn how to create a layout for your website! This is an important foundation for a scalable website structure.

{% verbatim %} You can browse this Spincast website sources themselves to see how we use such layout using some {% block %}. The layout.html file is the root of our layout. {% endverbatim %}

Provided functions and filters

Spincast provides some functions and filters for Pebble out of the box. They are defined in the SpincastPebbleExtensionDefault class.

Functions

  • get(String pathExpression)

    This function receives the path to an element as a string, evaluates it, and returns the element if it exists or null otherwise. In other words, it allows you to dynamically create the path to an element. For example :

    {% verbatim %}

    
    {% set user = get("myForm.users[" + generateRandomPosition() + "]") %}
    {% if user is not null %}
        <p>The name of the random user is {{user.name}}</p>
    {% endif %}
    {% endverbatim %}

  • msg(String messageKey, ...params)

    This function displays a localized message taken from the Dictionary. Only the message key is required, but you can also pass some parameters to be evaluated.

    Example, without any parameters :

    {% verbatim %}

    
    <h1>{{ msg('app.home.title') }}</h1>
    
    {% endverbatim %}

    With parameters :

    {% verbatim %}

    
    <div>{{ msg('welcome.user', 'firstName', user.firstName, 'lastName', user.lastName) }}</div>
    
    {% endverbatim %}

    Note that each parameter's key must have an associated value or an exception will be thrown (the number of parameters must be even).

    Finally, if the first parameters is true, the evaluation of the message will be forced, even if no parameters are provided. Indeed, to improve performance, by default a message from the dictionary is only evaluated using the Templating Engine if at least one parameter is provided. Example of forcing the evaluation:

    {% verbatim %}

    
    <h1>{{ msg('app.display.date', true) }}</h1>
    
    {% endverbatim %}

  • jsOneLine(String code)

    This function allows the output of javascript code inside quotes. It removes newlines and properly escapes the quotes in the code.

    {% verbatim %}

    
    let js="{{jsOneLine(code)}}";
    
    {% endverbatim %}

    You can pass true as a second parameter if single quotes needs to be escaped instead of double quotes:

    {% verbatim %}

    
    let js='{{jsOneLine(code, true)}}';
    
    {% endverbatim %}

  • querystring(String querystring)

    This function will add the specified querystring to the existing one. In other words, the querystring of the current request will be kept, but the specified one will be concatenated to it.

    If a parameter name already exist in the current querystring, it is overwritten.

    {% verbatim %}

    
    <a href="{{ querystring('?offset=' + newOffset) }}">link</a>
    
    {% endverbatim %}

    If the previous example was evaluated part of a "https://example.com?limit=10" request, the resulting content would be something like "<a href="?limit=10&offset=10">link</a>"

    Finally, note that if this function is called without being inside a request context, the specified querystring will simply be used as is.

  • querystringToHiddenFields(String querystring)

    This function takes all the parameters of the current querystring and converts them to hidden fields (ie: <input type="hidden" name="xxx" value="yyy" />).

    This mainly allows a GET form to keep current parameters when it is submitted. For example:

    {% verbatim %}

    <form class="resultsCtrlWrap" method="get">
        {{ querystringToHiddenFields() }}
        
        <input type="submit" value="Submit!" />
    </form>
    
    {% endverbatim %}

    If this form was displayed on a /myPage?someKey=someValue url,"someKey=someValue" would be on the url the form would be submitted to.

    The function takes an optional parameter which is a list of parameters to ignore. For example:

    {% verbatim %}

    
    {{ querystringToHiddenFields(['orderBy', 'filter']) }}
    
    {% endverbatim %}

  • isRoute(String path, [boolean isRegEx, boolean allowSubPaths])

    This function returns true if the specified path matches the route of the current request.

    For example:

    {% verbatim %}

    
    <span class="menu {% if isRoute('/users') %}active{% endif %}"</span>
    
    {% endverbatim %}

    If the second parameter is "true", the specified path will be considered as a regular expression:

    {% verbatim %}

    
    <span class="menu {% if isRoute('/(user|users)', true) %}active{% endif %}"</span>
    
    {% endverbatim %}

    Finally, if the third parameter is "true", any subpath of the specified path will also match! If the specified path is a regular expression, then "(/?$|/.*)" will be concatenated to it. If the path is not a regular expression, Spincast will use "startWith(path)" instead of "equals(path)" to validate the current route:

    {% verbatim %}

    
    // Will match "/users", "users/123", "users/123/books/456"
    <span class="menu {% if isRoute('/users', false, true) %}active{% endif %}"</span>
    
    // Will match "/user", "/user/123/books/456", "/users/", "/users/123/books/456"
    <span class="menu {% if isRoute('/(user|users)', true, true) %}active{% endif %}"</span>
    
    
    {% endverbatim %}

    If this function is evaluated outside of a request context (for example from a scheduled task), then false is returned.

  • isRouteId(String routeId)

    This function returns true if the specified id is the id of the current route.

    For example:

    {% verbatim %}

    
    <span class="menu {% if isRouteId('myUsersRouteId') %}active{% endif %}"</span>
    
    {% endverbatim %}

    If this function is evaluated outside of a request context (for example from a scheduled task), then false is returned.

Filters

  • pathExpression | get()

    This filter does the same as the get() function : it receives the path to an element as a string, evaluates it, and returns the element if it exists or null otherwise.

    The difference with the get() function is that you can use undefined elements with this filter and no exception is going to be thrown, even if strictVariables is on.

    {% verbatim %}

    
    {% set user = "may.not.exist.users[" + generateRandomPosition() + "]" | get() %}
    {% if user is not null %}
        <p>The name of the random user is {{user.name}}</p>
    {% endif %}
    {% endverbatim %}

  • someText | newline2br()

    This filter will replace the newlines of the text with <br />\n. This is useful when you want to display some text in an HTML template while respecting the newlines.

    {% verbatim %}

    
    {{ someText | newline2br }}
    
    {% endverbatim %}

    By default, the rest of the text will be properly escaped. For example, "<em>a\nb</em>" will become "&lt;em&gt;a<br />\nb&lt;/em&gt;".

    To disable the escaping, pass false as a parameter:

    {% verbatim %}

    
    {{ someText | newline2br(false) }}
    
    {% endverbatim %}

    This would result in "<em>a<br />\nb</em>".

  • someVar | boolean()

    This filter converts a "true" or "false" string to a proper boolean. This allows the string variable to be used in if statements.

    {% verbatim %}

    
    // Let's say val is "true" (a string) here...
    
    {% if val | boolean %}ok{% endif %}
    
    {% endverbatim %}

    The main use case for this filter is when a form is submitted and contains a boolean field which is transformed to a string value. When redisplaying the form, you may need to interpret the value of the field as a true boolean to perform logic.

    If the variable is already a boolean, it will also work fine.

  • someElements | checked(String[] matchingValues)

    This filter outputs the string "checked" if at least one element from someElements matches one of the element from the matchingValues. Both sides can either be a single element or an array of elements. For example :

    {% verbatim %}

    <label for="drinkTea">
        <input type="radio" 
               id="drinkTea" 
               name="user.favDrink"
               {{user.favDrink | checked("tea")}}
               value="tea"/> Tea</label>
    {% endverbatim %}

    Note that the elements are compared using equivalence, not using equality. So the String "true" matches the true boolean and "123.00" matches 123, for example.

  • someElements | selected(String[] matchingValues)

    This filter outputs the string "selected" if at least one element from someElements matches one of the element from the matchingValues. Both sides can either be a single element or an array of elements. For example :

    {% verbatim %}

    <select name="user.favDrink" class="form-control">
        <option value="tea" {{user.favDrink | selected("tea")}}>Tea</option>
        <option value="coffee" {{user.favDrink | selected("coffee")}}>Coffee</option>
        <option value="beer" {{user.favDrink | selected("beer")}}>WBeer</option>
    </select>
    {% endverbatim %}

    Note that the elements elements are compared using equivalence, not using equality. So the String "true" matches the true boolean and "123.00" matches 123, for example.

The remaining filters are all about validation. Make sure you read the dedicated Validation Filters section to learn more about them and to see some examples!

  • ValidationMessages | validationMessages()

    This filter uses a template fragment to output the Validation Messages associated with a field.

  • ValidationMessages | validationGroupMessages()

    This filter is similar to validationMessages() but uses a different template. It is made to output the Validation Messages of a group of fields, instead of a single field.

  • ValidationMessages | validationClass()

    The validationClass(...) filter checks if there are Validation Messages and, if so, it outputs a class name.

  • ValidationMessages | validationFresh()
    ValidationMessages | validationSubmitted()

    Those two filters are used to determine if a form is displayed for the first time, or if it has been submitted and is currently redisplayed with potential Validation Messages.

  • ValidationMessages | validationHasErrors()
    ValidationMessages | validationHasWarnings()
    ValidationMessages | validationHasSuccesses()
    ValidationMessages | validationIsValid()

    Those four filters check if there are Validation Messages of a certain level and return true or false.





© 2015 - 2024 Weber Informatics LLC | Privacy Policy