HTL - bartoszWesolowski/aem-tips GitHub Wiki
- separates logic from presentation
- simple to write and understand
- Comparators works similar to JS comparators
==
=>JS ===
,!=
=>JS !==
-
<
,>
,<=
,>=
comparators for numbers supported
${enumConstant == 'CONSTANT_NAME'} <!-- Java Enum comparison -->
${'a' in 'abc'} <!--/* returns true */-->
${'ab' in 'abc'} <!--/* returns true */-->
${'bc' in 'abc'} <!--/* returns true */-->
${'abc' in 'abc'} <!--/* returns true */-->
${'d' in 'abc'} <!--/* returns false */-->
<!--/*
Assuming myArray would be in scope and would have the following content:
[100, 200, 300, 400, 500]
*/-->
${100 in myArray} <!--/* returns true */-->
${300 in myArray} <!--/* returns true */-->
${1 in myArray} <!--/* returns false */-->
<!--/*
Assuming logic is a map
{
a: true,
b: 'two',
c: 3
}
*/-->
${'a' in logic} <!--/* returns true */-->
${'b' in logic} <!--/* returns true */-->
${'c' in logic} <!--/* returns true */-->
${'two' in logic} <!--/* returns false */-->
- HTL comment will not be included in the HTML output
<!--/* The content of this comment will be removed from the output. */-->
- HTL expressions inside HTML comments are evaluated, comment content visible in HTML
<!--/* Numbered parameters for injecting variables: */-->
${'Asset {0}' @ format=properties.assetName} <!--/* Basically a shortcut of the array notation, useful when it has only one element */-->
${'Asset {0}' @ format=[properties.assetName]}
${'Asset {0} out of {1}' @ format=[properties.current, properties.total]}
${'Asset {0} out of {1}' @ format=[properties.current, properties.total], i18n, locale='de'}
output
Asset Night Sky
Asset Night Sky
Asset 3 out of 5
Bild 3 von 5
assuming that
properties.assetName = 'Night Sky'
properties.current = 3
properties.total = 5
formatter 'Asset {0} out of {1}' will be translated to 'Bild {0} von {1}' for the 'de' locale by i18n
- Sets the content of current element - element content is replaced with given value.
- Value required
- Basic example
============ Markup ============
<p data-sly-text="Hello world">This text would never be shown.</p>
============ Output ============
<p>Hello world</p>
- Whole content is replaced with given text
============ Markup ============
<div data-sly-text="Text provided in data-sly-text">
<p>some text in p element</p>
<div>some other element</div>
</div>
============ Output ============
<div>
Text provided in data-sly-text
</div>
- If value is empty it will display given tag with no content
============ Markup ============
<div data-sly-text="${null}">
<p>data-sly-text with null value</p>
<div>this will not be rendered</div>
</div>
============ Output ============
<div></div>
- Other examples from documentation
<p data-sly-text="${''}"></p> <!--/* outputs: */--> <p></p>
<p data-sly-text="${[]}"></p> <!--/* outputs: */--> <p></p>
<p data-sly-text="${0}"></p> <!--/* outputs: */--> <p>0</p>
<p data-sly-text="${false}"></p> <!--/* outputs: */--> <p>false</p>
- By default context is set to text but it can be changed
============ Markup ============
<p data-sly-text="${'<strong>Bold and Proud</strong>' @ context='html'}"></p>
============ Output ============
<strong>Bold and Proud</strong>
Without context change the default one is used and text is escaped:
============ Markup ============
<p data-sly-text="${'<strong>Bold and Proud</strong>'}"></p>
============ Output ============
<strong>Bold and Proud</strong>
- Sets an attribute or a group of attributes on the current element.
- Attribute value: optional; String for setting attribute content, or Boolean for setting boolean attributes, or Object for setting multiple attributes; removes the attribute if the value is omitted.
- Attribute identifier: optional; the attribute name; must be omitted only if attribute value is an Object.
- Attributes are processed left to right (last value will be used in case multiple attributes with same name are present)
<!--/* given object
foobar = {'id': 'foo', 'class': 'bar', 'lang': ''}
*/-->
============ Markup ============
<div class="bar1" data-sly-attribute.class="bar2" data-sly-attribute="${foobar}"></div>
============ Output ============
<div id="foo" class="bar"></div>
============ Markup ============
<div data-sly-attribute="${foobar}" data-sly-attribute.class="bar2" id="foo2"></div>
============ Output ============
<div id="foo2" class="bar2"></div>
- Last attr is always counted - even if it does not use data-sly-attribute directive
============ Markup ============
<p data-sly-attribute.title="Title 1" data-sly-attribute.title="${'Title evaluated'}"
data-sly-attribute.title="${null}" title="Title plain text">
============ Output ============
<p title="Title plain text"></p>
- Empty attribute with plain value (no HTL expression inside value) will be rendered
============ Markup ============
<p class="" data-sly-attribute.id=""></p>
============ Output ============
<p class=""></p>
- I case the last attribute value is empty then no attribute will be rendered
<div lang="${''}"></div>
<div lang="en" data-sly-attribute.lang></div>
<div lang="en" data-sly-attribute.lang=""></div>
<div lang="en" data-sly-attribute.lang="${''}"></div>
============ All of the above output ============
<!--/* All of the above output: */-->
<div></div>
- Empty attributes are left if no data-sly-attribute is used
============ Markup ============
<div title="" data-sly-attribute="${foobar}"></div>
============ Output ============
<div title="" id="foo" class="bar"></div>
- boolean atributes are supported
<input checked="${true}"/>
<input data-sly-attribute.checked="${true}"/>
<!--/* Both output: */-->
<input checked/>
<input checked="${false}"/>
<input data-sly-attribute.checked="${false}"/>
<!--/* Both output: */-->
<input/>
<!--/* But 'true' or 'false' strings don't work the same way: */-->
<input checked="${'true'}"/> <!--/* outputs: */--> <input checked="true"/>
<input checked="${'false'}"/> <!--/* outputs: */--> <input checked="false"/>
<!--/* Consider having attrs={'checked': true} */-->
<input data-sly-attribute="${attrs}"/>
<!--/* outputs: */-->
<input checked/>
- arrays
<div title="${['one', 'two', 'three']}"></div>
<!--/* outputs: */-->
<div title="one,two,three"></div>
<!--/* Like empty strings, empty arrays remove the attribute: */-->
<div title="${[]}"></div>
<!--/* outputs: */-->
<div></div>
<!--/* But an array containing just an empty string doesn't get removed: */-->
<div title="${['']}"></div>
<!--/* outputs: */-->
<div title=""></div>
- numbers are cast as strings
<div class="${0}"></div>
<!--/* outputs: */-->
<div class="0"></div>
- changes the element tag
<div data-sly-element="${'h1'}">Blah</div>
<div data-sly-element="h1">Blah</div>
============ Both Outputs ============
<h1>Blah</h1>
- given element has no value
<div data-sly-element="${''}">Blah</div>
<div data-sly-element="">Blah</div>
============ Both Outputs ============
<div >Blah</div>
- value uses context
elementName
with supported values:section, nav, article, aside, h1, h2, h3, h4, h5, h6, header, footer, address, main, p, pre, blockquote, ol, li, dl, dt, dd, figure, figcaption, div, a, em, strong, small, s, cite, q, dfn, abbr, data, time, code, var, samp, kbd, sub, sup, i, b, u, mark, ruby, rt, rp, bdi, bdo, span, br, wbr, ins, del, table, caption, colgroup, col, tbody, thead, tfoot, tr, td, th
- not supported values:
<script>, <style>, <form>, or <input>
<div data-sly-element="input">
some text
</div>
<div data-sly-element="script">
some text
</div>
============ Both Outputs ============
<div >some text</div>
- keeps or removes element depending on value
- content shown if evaluated to
true
<p data-sly-test.editOrDesign="${wcmmode.edit || wcmmode.design}">displays the content when in `edit` or `design` mode</p>
<p data-sly-test="${!editOrDesign && pageProperties.jcr:title}">displays the content when in `edit` or `design` mode and the `pageProperties` contain a non-empty `jcr:title` property</p>
- value evaluated as boolean but not cased when variable is defined
<p data-sly-test.myVar="${'foo'}">${myVar}</p>
<!--/* outputs: */-->
<p>foo</p>
- multiple test with same variable name (values evaluated from top to bottom)
<div data-sly-test.variable="${'variable in outer div'}">
Variable value="${variable}"
<p data-sly-test.variable="${'variable first div in inner p'}">Variable value in first div in p="${variable}"</p>
</div>
<div data-sly-test.variable="${'variable in second div'}">
Variable value in div sibling="${variable}"
<p>
Variable value in div sibling child p="${variable}"
</p>
</div>
============ Output ============
<div>
Variable value="variable in outer div"
<p>Variable value in first div in p="variable first div in inner p"</p>
</div>
<div>
Variable value in div sibling="variable in second div"
<p>
Variable value in div sibling child p="variable in second div"
</p>
</div>
- zero and empty array evaluates as false and will not render element
<div data-sly-test="${0}">Test 0 will NOT show the element</div>
<div data-sly-test="${' '}">Blank string evaluates to false</div>
<div data-sly-test="${[]}">Test empty array will NOT show the element</div>
- any other number or array containing some elements will evaluate to true
<div data-sly-test="${1}">Element will be visible</div>
<div data-sly-test="${-1}">Element will be visible</div>
<div data-sly-test="${['']}">Array with some elements - will be visible</div>
<div data-sly-test="${[0]}">Array with some elements - will be visible</div>
-
Iterates over the content of each item in the attribute value, allowing to control the iteration through the following options:
-
begin
- iteration begins at the item located at the specified index; first item of the collection has index 0 -
step
- iteration will only process every step items of the collection, starting with the first one -
end
- iteration ends at the item located at the specified index (inclusive)
-
-
If no value present no element will be shown
-
Usage
data-sly-list="${list}"
which is equivalent ofdata-sly-list.item="${list}"
-
Iteration metadata available in object
itemList
or<variable>List
if named variable used, for exampledata-sly-list.element="${list}"
will useelementList
iteration object with variables:-
index
: zero-based counter (0..length-1
); -
count
: one-based counter (1..length
); -
first
:true
for the first element being iterated; -
middle
:true
if element being iterated is neither the first nor the last; -
last
:true
for the last element being iterated; -
odd
:true
ifcount
is odd; -
even
:true
ifcount
is even.
-
-
given list
numbers = [a, b, c, d, e]
============ Markup ============
<ul data-sly-list.number="${numbers}">
<li>${number}</li>
</ul>
============ Output ============
<ul>
<li>a</li>
<li>b</li>
...
<li>e</li>
</ul>
- using begin and end parameters
============ Markup ============
<!--/* Iteration control; start from the beginning, stop after the first 3 elements (index 2) */-->
<ul data-sly-list.number="${numbers @ begin = 0, end = 2}}">
<li>${number}</li>
</ul>
============ Output ============
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
- using begin and end parameters when begin is grater than number of elements
============ Markup ============
<ul data-sly-list.number="${numbers @ begin = 5, end = 10}}">
<li>${number}</li>
</ul>
============ Output ============
<ul>
</ul>
- Iterating over map uses entry key for iteration object
<dl data-sly-list="${myMap}">
<dt>key: ${item}</dt>
<dd>value: ${myMap[item]}</dd>
</dl>
- Works in a same way that data-sly-list but repeats current element not element content (child nodes)
- given list
numbers = [a, b, c, d, e]
============ Markup ============
<ul>
<li data-sly-repeat.number="${numbers}">${number}</li>
</ul>
============ Output ============
<ul>
<li>a</li>
<li>b</li>
...
<li>e</li>
</ul>
- Includes the output of a rendering script run with the current context.
<div data-sly-include="template.html"></div>
- Only content of the included script is rendered
<!--/* template.html: */-->
<h1>Template html</h1>
============ Markup ============
<div class="include" data-sly-include="template.html"/></div>
============ Output============
<h1>Template html</h1>
- Parameters:
appendPath
andprependPath
:
<div data-sly-include="${'partials' @ appendPath='template.html'}"></div>
<!--/* will include partials/template.html */-->
<div data-sly-include="${'template.html' @ prependPath='partials'}"></div>
<!--/* will include partials/template.html */-->
<div data-sly-include="${'components' @ prependPath='partials', appendPath='template.html'}"></div>
<!--/* will include partials/components/template.html */-->