AEM different ways to use HTL sly - aem

What is the difference between to use:
<div data-sly-resource="${'foo' # resourceType="var"} ... ></div>
or
<sly data-sly-resource="${'foo' # resourceType="var"} ... ></sly>
or
<sly data-sly-resource="${'foo' # resourceType="var"} ... />
And when I should use data-sly-unwrap?

I think the best way to understand when to use what, is to understand the fundamentals of HTL.
Most of HTL can be written around existing HTML tags and attributes, such as
<div data-sly-resource="${'foo' # resourceType='var'}" ... ></div>
However, in instances where you don't want the HTML element to be present in the output, you can leverage the sly element. When an sly element is used it is removed from the final rendered HTML automatically.
For e.g.,
<sly data-sly-resource="${'foo' # resourceType='var'}" ... ></sly>
or
<sly data-sly-resource="${'foo' # resourceType='var'}" ... /> both output the same HTML which is directly including the output of the resource foo without adding any extra tags.
But if the same was written using an HTML element such as the following
<div data-sly-resource="${'foo' # resourceType=""var}" ... ></div>
the generated HTML will contain a parent div tag around the included resource's output as shown below
<div>HTML output of foo goes here</div>
The data-sly-unwrap comes into play in such scenarios. Adding the data-sly-unwrap to an HTML element will exclude that element from the generated output, but would output all the child HTML.
For e.g., <div data-sly-resource="${'foo' # resourceType='var'}" ... data-sly-unwrap></div> and <sly data-sly-resource="${'foo' # resourceType='var'}"></sly> and <sly data-sly-resource="${'foo' # resourceType='var'}" /> would produce the same output.
Please note that the data-sly-unwrap on a sly element has no effect as the sly is removed by the processor anyways.
However, I think the power of data-sly-unwrap lies when using it with conditional statements.
For e.g., if a parent element needs to present only in certain scenarios, then using it in the following way is much cleaner than writing multiple if conditions as we used to do in JSPs or JSTLs.
<div class="parent" data-sly-unwrap="${hideParent}">
<img class="img" src="../../xyz.jpg" />
</div>
More on data-sly-unwrap here.

Related

AEM - data-sly-resource children html

I want to figure out a way to insert HTML inside a <sly data-sly-resource> tag and be able to go inside the component I am retrieving from the resource attribute.
To compare, it would be something like Vue's slots, and React's { this.props.children }.
Example:
Parent Component
<sly data-sly-resource="${'example' # resourceType='path/to/component/structure/example'}">
<h1>Hello World</h1>
</sly>
Example Component
<div id="example-component">
${ variable.getChildrenHTMLCall() } // Does something like this exist?
</div>
Output
<div id="example-component">
<h1>Hello World</h1>
</div>
This functionality does not exist.
You could make a similar functionality by using data-sly-template. But you’d have to pass the HTML sting as a parameter (more specifically option) but that might not be desired or maintainable.
You could use the com.day.cq.contentsync.handler.util.RequestResponseFactory as seen here: http://www.nateyolles.com/blog/2015/10/get-rendered-html-for-an-aem-resource-or-component

Is there a pattern for grouping templates via includes?

I'm creating a new project, and I'd like to namespace a few of my helpers for sightly. These helpers are "template.html files". I'm currently calling them with the normal pattern of:
<sly data-sly-use.MyHelper='MyHelper.html' data-sly-call="${MyHelper.tmpl # args..}"/>
What I'm appreciating about Sightly is the fact that I can do something like this:
templates.html
<template data-sly-template.one>1</template>
<template data-sly-template.two>2</template>
main.html
<sly data-sly-use.tmpls="templates.html"/>
one: <sly data-sly-call=${tmpls.one}/>
two <sly data-sly-call=${tmpls.two}/>
What I would like to set up is:
library.html (includes more modular template functionality)
<sly data-sly-import="one.html"/>
<sly data-sly-import="two.html"/>
main.html (imports library)
<sly data-sly-use.libs="library.html"/>
one: <sly data-sly-call=${libs.one}/>
two <sly data-sly-call=${libs.two}/>
I have tried a couple variations of the latter to see if there was already something OTTB that's supported. Perhaps I was just hooking it up incorrectly, but does anyone know if this is possible?
thank you,
Brodie
From the HTL Spec:
When templates are located in a separate file, they can be loaded with data-sly-use
You are already doing this in your working example with data-sly-use and data-sly-call in your main.html to the data-sly-template in your template.html. You just need to do it one more time in your library.html.
main.html (imports library)
<sly data-sly-use.libs="library.html"/>
one: <sly data-sly-call=${libs.one}/>
two <sly data-sly-call=${libs.two}/>
library.html (includes more modular template functionality)
<template data-sly-template.one>
<div data-sly-use.one="one.html" data-sly-call="${one.one}"></div>
</template>
<template data-sly-template.two">
<div data-sly-use.two="two.html" data-sly-call="${two.two}"></div>
</template>
one.html
<template data-sly-template.one>this is one</template>
two.html
<template data-sly-template.two>this is two</template>
This will allow you to import all your helpers via one data-sly-use expression while keeping your helper templates in separate files just as you asked for, even if the intermediary library.html isn't as succinct as you probably wanted.

How to set variable from use object in sightly?

I have plain use class which contains one method that returns complex bean with a lot of setters/getters. Lets name it SomeUse. Given sightly file:
<sly data-sly-use.someUse="com.mycompany.SomeUse">
${someUse.data.firstProperty}
<div>
${someUse.data.secondProperty}
</div>
<!-- ...and so on -->
</sly>
So the point is I don't want to look at someUse.data getting. Instead of it I would do something like this:
<sly data-sly-use.someUse="com.mycompany.SomeUse" data-sly-use.data=${someUse.data}>
${data.firstProperty}
<div>
${data.secondProperty}
</div>
<!-- ...and so on -->
</sly>
I can't do this way though. Is there any alternative to achieve such result? Thanks a lot!
So the answer is to:
<sly data-sly-test.varName="${data.firstProperty}"></sly>
<div> ${varName.secondProperty} </div>
Creating a variable through empty data-sly-test attribute make it accessible after a tag.
You can set variables for use in a WCMUse class with the following syntax:
<sly data-sly-use.someUse="${ 'com.mycompany.SomeUse' # page=currentPage }">
and retrieve the page variable from your WCMUse class's activate() method like this:
Page page = get("page", Page.class);
For a working example, check out this Sightly script and this WCMUse class.
Instead of data-sly-use.data=${someUse.data}
use data-sly-test.data="${someUse.data}".
Then you will be able to get the property like
${data.firstProperty}
<div>
${data.secondProperty}
</div>
You can also set in DOM elements
<div id="elementId" data-sly-test.vehicle="${model.vehicle}">
<p>${vehicle.name}</p>
<p>${vehicle.type}</p>
</div>

AEM 6 sightly: How to read variable from language file?

I have the following html:
<div >${'foo' # i18n}</div>
In my i18n file I have the following:
<foo
jcr:mixinTypes="[sling:Message]"
jcr:primaryType="sling:MessageEntry"
sling:key="foo"
sling:message="This is dummy text"/>
This is dummy text is displayed in the page. well so far. The problem is that foo is a variable which comes form other template and I read as follow:
${fooValue} //this returns foo
Now to read message from the i18n I tried the following:
<div>${'${fooValue}' # i18n} </div>
but This displays ${fooValue} in the page. How to read message from the i18n, if I have variable key?
You could use a local template to which you pass the variable identifying your key for the i18n dictionary:
<template data-sly-template.locale="${# key}">
${key # i18n, locale='de'}
</template>
<div data-sly-call="${locale # key='world'}"></div>
Assuming your i18n dictionary has the translation, the output would be:
<div>
Welt
</div>
You can also call the locale template from another template in your page:
<template data-sly-template.locale="${# key}">
${key # i18n, locale='de'}
</template>
<template data-sly-template.translate="${# string}">
<div data-sly-call="${locale # key=string}" data-sly-unwrap></div>
</template>
<div data-sly-call="${translate # string='world'}"></div>
The output would be the same as above.
The solution by Radu works wonderfully. I have also tried this and this works too, if anyone is looking for a solution without involving templates.
<div>${fooValue # i18n}</div>
I personally would go with templates though. Makes it a little easier to read.
<div>${fooValue # i18n}</div> vs <div data-sly-call="${translate # string=fooValue}"></div>.

Evaluating expression and pass as argument in Sightly AEM

I have the following Sightly expression:
<li data-sly-call="${linkTemplate.dynamicLink # section='education',
url='/en/life-career-events.html', text=${'comp.masthead.navigation.home' # i18n}}">
</li>
The dynamiclink template is as follows:
<div data-sly-template.dynamicLink="${# section, url, text}"
data-sly-use.membersNav="${'com.comp.cms.component.masthead.MembersNavigation' # section=section}">
<a data-sly-attribute.class="${membersNav.cssClass}" href="${url}">${text}</a>
</div>
This doesn't work because text=${'comp.masthead.navigation.home' # i18n} isn't evaluated as a string and then passed into the dynamiclink.
Is this possible? Can I evaluate and assign to a variable or do I have to create a new template when I want to evaluate i18n lookups?
Sightly 1.1 doesn't allow to have expressions within expressions, and there's no plan to change that for now.
Hacking the solution:
There's a trick: data-sly-test can be (ab)used to set variables. It's not really a recommended way to do though, unless you have a real condition, because this will mislead someone who reads the template in thinking that the intention was to have an actual condition.
The trick goes like that: an identifier can be provided to data-sly-test, which will expose the result of the test as a variable. Additionally, data-sly-test will be considered true, unless the resulting string is empty.
For e.g.:
<p data-sly-test.spanishAsset="${'Asset' # i18n, locale='es'}">${spanishAsset}</p>
Outputs:
<p>Recurso</p>
So in your case, you could write:
<li data-sly-test.linkText="${'comp.masthead.navigation.home' # i18n}"
data-sly-call="${linkTemplate.dynamicLink # section='education',
url='/en/life-career-events.html', text=linkText}">
</li>
A cleaner solution
As you probably don't want to explain to all the users of this template that they have to write such a hack, and instead of having two separated templates for translated and non-translated texts, you could instead leverage optional templates parameters. So you might for e.g. have a noI18n optional parameter.
The call would then be as simple as it can be:
<!--/* Translating would be the default behavior */-->
<li data-sly-call="${linkTemplate.dynamicLink #
section='education',
url='/en/life-career-events.html',
text='comp.masthead.navigation.home'}"></li>
<!--/* Or translating could be turned off */-->
<li data-sly-call="${linkTemplate.dynamicLink #
section='education',
url='/en/life-career-events.html',
text='my text...',
noI18n=true}"></li>
The template would then have two data-sly-test conditions for the two cases (note that the data-sly-unwrap attributes can be dropped in AEM 6.1+):
<div data-sly-template.dynamicLink="${# section, url, text, noI18n}"
data-sly-use.membersNav="${'com.comp.cms.component.masthead.MembersNavigation'
# section=section}">
<a href="${url}" data-sly-attribute.class="${membersNav.cssClass}">
<sly data-sly-test="${noI18n}" data-sly-unwrap>${membersNav.text}</sly>
<sly data-sly-test="${!noI18n}" data-sly-unwrap>${membersNav.text # i18n}</sly>
</a>
</div>
Optionally, to keep the template as simple as possible and to remove those conditions, you could also make the Use-API do the translation, depending on the noI18n optional parameter:
<div data-sly-template.dynamicLink="${# section, url, text, noI18n}"
data-sly-use.membersNav="${'com.comp.cms.component.masthead.MembersNavigation'
# section=section, noI18n=noI18n}">
<a href="${url}" data-sly-attribute.class="${membersNav.cssClass}">
${membersNav.text}
</a>
</div>
The proper code for the logic to translate a string is:
Locale pageLang = currentPage.getLanguage(false);
I18n i18n = new I18n(slingRequest.getResourceBundle(pageLang));
String text = i18n.get("Enter a search keyword");

Categories