April 26, 2020
Estimated Post Reading Time ~

HTL (Sightly) Code Snippets

Below are a few HTL syntax used frequently in AEM.

1. HTL does not support JSP tag libraries.

2. Including a script: data-sly-include instead of cq:include
<cq:include script="template.html"/> //Including a HTL file in JSP
<sly data-sly-include="template.jsp"/> //Including a JSP file in HTL

The element on which a data-sly-include has been set is ignored and not displayed.

3. Including a Resource: data-sly-resource
Includes the result of rendering the indicated resource through the sling resolution and rendering process. Basic syntax-

<article data-sly-resource="path/to/resource"></article>

Override resourceType of an include-
<article data-sly-resource="${'path/to/resource' @ resourceType='my/resource/type'}"></article>

Change the wcmmode-
<article data-sly-resource="${'path/to/resource' @ wcmmode='disabled'}"></article>

4. Changing element tag: data-sly-element
This replaces the element name of the host element-
<h1 data-sly-element="${titleLevel}">text</h1>

Replaces the h1 with the value of titleLevel.

For security reasons, data-sly-element accepts only limited element names.
5. Including clientlibs: data-sly-use and data-sly-call
In a single statement-

<sly data-sly-use.clientlib="/libs/granite/sightly/templates/clientlib.html"
data-sly-call="${clientlib.all @ categories=['myCategory1', 'myCategory2']}"/>

In Separate statements-

<!doctype html>
<html data-sly-use.clientlib="/libs/granite/sightly/templates/clientlib.html">
<head>
<!-- HTML meta-data -->
<css data-sly-call="${clientlib.css @ categories='myCategory'}"/>
</head>
<body>
<!-- page content -->
<js data-sly-call="${clientlib.js @ categories='myCategory'}"/>
</body>
</html>

6. If Statement: data-sly-test
HTL uses data-sly-test block statement to implement "if" behavior. There is no direct if-else implementation. You need to utilize data-sly-test in an efficient manner to achieve this.

A). Positive condition: if
<h1 data-sly-test="${properties.jcr:title}"> ${properties.jcr:title}</h1>
Negative condition: else
<h1 data-sly-test="${!properties.jcr:title}"> ${pageProperties.name | "Untitled" }</h1>

You can also use relational operators i.e.- "<=", ">=", "==" etc. in your test condition.

B). Always cache test block statement results in an identifier if it repeats itself

<h1 data-sly-test.hasTitle="${properties.jcr:title}"> ${properties.jcr:title}</h1> //if
<h1 data-sly-test="${!hasTitle}"> ${pageProperties.name | "Untitled" }</h1> //else

7. data-sly-unwrap/ sly Element
AEM 6.0 (HTL1.0) has an attribute "data-sly-unwrap" to avoid rendering of referenced HTML tag in context.

<!-- /* This */ -->
<p data-sly-use.nav="navigation.js" data-sly-unwrap>Hello World</p>

<!-- /* Produces */ -->
Hello World

<!-- /* you can also put condition in data-sly-unwrap */ -->

<p data-sly-unwrap="${someCondition}">Hello World</p>

The above statement will render the hosting element only when the condition evaluates to false.

AEM 6.1 (HTL1.1) has introduced a new element- "sly" to achieve this. So it is suggested to use sly statement instead of data-sly-unwrap in HTL 1.1 onwards.

<sly data-sly-test="${someCondition}">Hello World</sly>

8. Iterating through a list: data-sly-list Element
<ul data-sly-list="${listObject}">
<li>Index: ${itemList.index}, Value: ${item}</li>
</ul>

Here itemList provides following properties-
index : counter (0-n)
count : counter (1-n)
first : if the current item is the first item
middle: if the current item is neither the first nor the last item
last: if the current item is the last item
odd: if index is odd
even: if index is even
You can also rename the item/ itemList variable name (This is suggested approach to use identifiers instead of using default item naming)-

<dl data-sly-list.child="${currentPage.listChildren}">
<dt>index: ${childList.index}</dt>
<dd>value: ${child.title}</dd>
</dl>

9. Use of Display Context
To protect against cross-site scripting (XSS) vulnerabilities, HTL automatically recognises the context within which an output string is to be displayed within the final HTML output, and escapes that string appropriately.

<p style="color: ${properties.color @ context='styleToken'};"></p>
<p>URL: ${teaser.link @ context = 'uri'}</p>

${properties.jcr:title @ context='html'} <!--/* Use for HTML output. Removes markup posing XSS risks */-->
${properties.jcr:title @ context='text'} <!--/* Use for plain text content - Encodes all HTML */-->
${properties.jcr:title @ context='elementName'} <!--/* Allows only white-listed element names, outputs 'div' otherwise */-->
${properties.jcr:title @ context='attributeName'} <!--/* Outputs nothing if the value doesn't map to a valid HTML attribute; Doesn't allow 'style' and 'on*' attributes */-->
${properties.jcr:title @ context='attribute'} <!--/* Applies HTML attribute escaping */-->
${properties.jcr:title @ context='uri'} <!--/* Outputs nothing if the value contains XSS risks */-->
${properties.jcr:title @ context='scriptToken'} <!--/* Outputs nothing if value doesn't correspond to the JavaScript token syntax */-->
${properties.jcr:title @ context='scriptString'} <!--/* Applies JavaScript string escaping */-->
${properties.jcr:title @ context='scriptComment'} <!--/* Context for Javascript block comments. Outputs nothing if value break out of the comment context */-->
${properties.jcr:title @ context='scriptRegExp'} <!--/* Applies JavaScript Regex escaping */-->
${properties.jcr:title @ context='styleToken'} <!--/* Outputs nothing if the value doesn't correspond to the CSS token syntax */-->
${properties.jcr:title @ context='styleString'} <!--/* Applies CSS string escaping */-->
${properties.jcr:title @ context='styleComment'} <!--/* Context for CSS comments. Outputs nothing if value break out of the comment context */-->
${properties.jcr:title @ context='comment'} <!--/* Applies HTML comment escaping */-->
${properties.jcr:title @ context='number'} <!--/* Outputs zero if the value is not a number */-->
${properties.jcr:title @ context='unsafe'} <!--/* Use at your risk, this disables XSS protection */-->

10. HTL Comments:<!--/* An HTL Comment */-->

11. Formatting in Expression:
To format string, you can use Numbered parameters for injecting variables:

${'Assets {0}' @ format=properties.assetName} <!--/* A shortcut of the array notation, useful when it has one element */-->
${'Assets {0}' @ format=[properties.assetName]}
${'Assets {0} - {1} of {2}' @ format=[properties.first, properties.last, properties.total]}

12. i18n: Internationalization
Following syntax is used to localize string literals in HTL-

${'Assets' @ i18n} <!--/* Translates the string to the resource language */-->
${'Assets' @ i18n, locale='en-US', hint='Translation Hint'} <!--/* Complete syntax with locale and hint options */-->

The i18n option can be combined with the format option, which replaces the placeholders after the string has been run through the dictionary:

${'Assets {0} - {1} of {2}' @ i18n, format=[properties.first, properties.last, properties.total]}

13. Array Join: Implode function
The join option allows controlling the output of an array object by specifying the separator string.

${['one', 'two'] @ join='; '} <!--/* outputs: one; two */-->

14. URI Manipulation
Following options are available-
scheme (To prepend with http/ https)
${'http://example.com/path/page.html' @ scheme='https'} <!-- outputs: https://example.com/path/page.html -->
domain
${'///path/page.html' @ domain='example.org'} <!-- outputs: //example.org/path/page.html -->
path
${'http://example.com/this/one.selector.html/suffix?key=value#fragment' @ path=''} <!-- outputs: http://example.com/this/one.selector.html/suffix?key=value#fragment -->
prependPath
appendPath
${'path/page.selector.html/suffix?key=value#fragment' @ appendPath='appended'} <!-- outputs: path/page/appended.selector.html/suffix?key=value#fragment -->
selectors
addSelectors
removeSelectors
extension
${'path/page.json#fragment' @ extension='html'} <!-- outputs: path/page.html#fragment -->
suffix
${'path/page.html?key=value' @ suffix='my/suffix'} <!-- outputs: path/page.html/my/suffix?key=value -->
prependSuffix
appendSuffix
query
${'http://www.example.org/search?s=1&q=htl' @ query} <!-- outputs: http://www.example.org/search -->
addQuery
removeQuery
fragment
${'path/page#one' @ fragment='two'} <!-- outputs: path/page#two -->
Use hashmap in sightly / HTL

WCMUsePojo code
package com.kishore.sightly; public class GetMap extends WCMUsePojo { Map<String, String> myMap = null; @Override public void activate() throws Exception { myMap = new HashMap<String, String>(); myMap.put("name", "Kishore"); } public Map<String, String> getmyMap() { return myMap; } }

HTL code

<sly data-sly-use.model="com.kishore.sightly.GetMap" /> Name: ${model.myMap['name']}


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.