AEM6.5 Passing paramater to the resource from HTL/Sightly template - aem

I have a component that uses two different resources in its HTL/Sightly template.
Is there a way to pass a parameter, to the say in my example the eventResource template, so that I can depending on this passed paramter change a css class on it?
<ul data-sly-list.teasers="${model.resourceList}" class="teaser-list-alternating c-list--reset">
<sly data-sly-test="${teasers.eventTeaser}"
data-sly-resource="${teasers.resource # resourceType='xxx/components/content/eventTeaser'}"></sly>
<li data-sly-test="${teasers.contentTeaser}" class="l-stack l-stack--horse"
data-component-hook-content-hub="teaser"
data-sly-resource="${teasers.resource # resourceType='xxx/components/content/contentHubTeaser'}"></li>
</ul>
I tried using data-sly-resource="${teasers.resource # resourceType='xxx/components/content/eventTeaser', requestAttributes=model.config, selectors='blabla'} to no availability.
#RequestAttribute(name = "contentHub")
private String contentHub;
The requestAttribute contentHub in the eventTeaser model is alway null and I am not sure how to get the selectors value in the eventTeaser template.
I can do it using TypeScript on the front end part but it is not very clean.

I was able to solve it using the selectors indeed and reading the selector value directly from the other sightly template. Here is the documentation I refered to:
data-sly-resource="${teasers.resource # resourceType='xxx/components/content/eventTeaser', requestAttributes=model.config, selectors='inContentHub'}
 In the eventTeaser template I then used the following:
data-sly-set.inContentHub="${'inContentHub' == request.requestPathInfo.selectorString}
and depending on the value of the inContentHub variable I was able to change the css class which was my ultimate goal.

Related

assign custom function call to variable

I am quite new to Typo3 and Fluid, but I guess what I am after is quite basic.
As an Analogy: Twig can extended, so it is possible to create a custom function which can be used like that:
{% set id = uid() %}
<input id="{{ id }}" … /><label for="{{ id }}">…</label>
Is such a thing possible with Fluid? Do I need to install other extensions, or can that be done with basic fluid extension?
In Fluid you have two ways to achieve this:
Prepare the desired data in the controller and assign it to the view as variable.
Create a custom viewhelper which contains the logic to build the desired data.
You can also combine these two and store the result of a viewhelper call in a variable using the f:variable viewhelper (more usage examples):
<f:variable name="myvariable">{acme:custom.viewhelper()}</f:variable>
In this specific case you can also install the VHS extension, the swiss army knife of Fluid, and use its UniqIdViewHelper Notice that you normally don't need this for forms since you bind them to (domain) objects you want to create/edit and let Extbase/Fluid handle the rest.

AEM 6.x: How to pass an HTL variable to clientlib/JS?

So I have the following lines which loads my javascript.
<sly data-sly-use.clientLib="${'/libs/granite/sightly/templates/clientlib.html'}" data-sly-unwrap />
<sly data-sly-call="${clientLib.js # categories='myhost.mycustomJS'}" data-sly-unwrap />
I have an HTL property (example: ${properties.myCustomProperty}) that I want to pass to myCustomJS.
Any ideas how it can be done?
I've looked around the net but didn't find anything useful.
Thank you.
You are trying to access a server side property with client side script. As you may realize sightly executes at server end and rendered output is returned to browser. In your case you need to send the properties to browser to make it available for clientside scripts to consume.
Technique 1: (Recommended) Data attributes -
This is easiest to send since DOM structure doesnt change. Pass the values as data elements and retrieve using jquery. For example:
var value = $('#mydiv').data('custom-property');
console.log(value);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="mydiv" data-custom-property="${properties.myCustomProperty}" />
Technique 2: (Old school) - Hidden variable - Add hidden variable into component rendering script; set the value of variable with HTL property and read the variable from clientside js using getElementById or jquery.
Technique 3: (Not recommended) - Make a trip to server. If you dont want to dilute your DOM (maybe property is secret or not SEO friendly), you may need to make an ajax call to a sling servlet that returns the property value. There are multiple examples available for sling servlet you can refer to.
ACS Sample, AEM 6.3 servlet, 1 more example.
But do remember its not worth to make a trip to server just for 1 property.

How can I include content of a component in Fabricator Assemble *without* a corresponding attribute, or at block level?

In Fabricator Assemble, I could have a component button.html:
<a class="button">{{text}}</a>
I can use this with the syntax {{>button text='Home'}}. Notably, I have to specify a name for the "text" attribute.
I'm looking to see how I can handle not needing to do that in Assemble. The Literals section of the docs for Handlebars (whiich Fabricator Assemble is built on) highlights an alternative syntax with which I could include a button:
{{>button 'Home'}}
In this example, "Home" is a value without any name for it at all. Handlebars also indicates the following is possible as a basic block:
{{#button}}
<b>Some button content</b>
{{/button}}
Likewise, that content has no name.
I'd like to be able to do this same thing in Fabricator Assemble, but it doesn't seem to have a way for me to include this nameless content. In templates there's {% body %} but that doesn't work here.
In Handlebars, which Fabricator Assemble is based on, all examples for how to recreate this involve JavaScript, which doesn't translate well to Assemble.
What can I do to use {{>button 'Some text'}} or {{#button}}...{{/button}} syntax in Fabricator Assemble? Is this behaviour even available?
In the current version, the easiest way to achieve this is with a custom helper.
Add the following to the helpers option in your gulpfile.js:
default: (value, defaultValue) => {
return value || defaultValue;
},
Then inside a handlebars template:
<div>
{{default varName 'default value'}}
</div>

AEM 6.0: Additional parameters when using data-sly-resource?

I am trying to implement something which I hope is relatively straight forward... I have one component (lets call it the wrapper component) which contains another component (lets call it the inner component) inside it via the data-sly-resource tag:
<div data-sly-resource="${ 'inner' # resourceType='/projectname/components/inner' }"></div>
I would like to pass in some additional parameters with this tag, specifically a parameter that can be picked up by sightly in the inner component template? I am trying to specify whether the inner templates outer html tag is unwrapped based on a parameter being passed in when the component is called via data-sly-resource.
After experimenting and perusing the sightly documentation, I can't find a way of achieving this.
Does anyone know if this is possible?
Many thanks,
Dave
You can use the Use-API to write and read request attributes if the alternatives proposed here don't work for you.
A quick example of two components where the outer component sets attributes that are then displayed by the inner component:
/apps/siteName/components/
outer/ [cq:Component]
outer.html
inner/ [cq:Component]
inner.html
utils/ [nt:folder]
setAttributes.js
getAttributes.js
/content/outer/ [sling:resourceType=siteName/components/outer]
inner [sling:resourceType=siteName/components/inner]
/apps/siteName/components/outer/outer.html:
<h1>Outer</h1>
<div data-sly-use="${'../utils/setAttributes.js' # foo = 1, bar = 2}"
data-sly-resource="inner"></div>
/apps/siteName/components/inner/inner.html:
<h1>Inner</h1>
<dl data-sly-use.attrs="${'../utils/getAttributes.js' # names = ['foo', 'bar']}"
data-sly-list="${attrs}">
<dt>${item}</dt> <dd>${attrs[item]}</dd>
</dl>
/apps/siteName/components/utils/setAttributes.js:
use(function () {
var i;
for (i in this) {
request.setAttribute(i, this[i]);
}
});
/apps/siteName/components/utils/getAttributes.js:
use(function () {
var o = {}, i, l, name;
for (i = 0, l = this.names.length; i < l; i += 1) {
name = this.names[i];
o[name] = request.getAttribute(name);
}
return o;
});
Resulting output when accessing /content/outer.html:
<h1>Outer</h1>
<div>
<h1>Inner</h1>
<dl>
<dt>bar</dt> <dd>2</dd>
<dt>foo</dt> <dd>1</dd>
</dl>
</div>
As commented by #AlasdairMcLeay, this proposed solution has an issue in case the inner component is included multiple times on the request: the subsequent instances of the component would still see the attributes set initially.
This could be solved by removing the attributes at the moment when they are accessed (in getAttributes.js). But this would then again be a problem in case the inner component is split into multiple Sightly (or JSP) files that all need access to these attributes, because the first file that accesses the request attributes would also remove them.
This could be further worked-around with a flag telling wether the attributes should be removed or not when accessing them... But it also shows why using request attributes is not a good pattern, as it basically consists in using global variables as a way to communicate among components. So consider this as a work-around if the other two solutions proposed here are not an option.
There is a newer feature that request-attributes can be set on data-sly-include and data-sly-resource :
<sly data-sly-include="${ 'something.html' # requestAttributes=amapofattributes}" />
Unfortunately it doesn't seem to be possible to construct a Map with HTL (=Sightly) expressions, and I don't see a way to read a request attribute from HTL, so you still need some Java/Js code for that.
unfortunately, no. there is no way to extend sightly functionality. you cannot add new data-sly attributes or modify existing ones. The best you can do is write your own helper using the USE API
If you just need to wrap or unwrap the html from your inner component in different situations, then you can just keep the html in the component unwrapped, and wrap it only when needed by using the syntax:
<div data-sly-resource="${ 'inner' # resourceType='/projectname/components/inner', decorationTagName='div', cssClassName='someClassName'}"></div>
If you need more complex logic, and you need to pass a value to your inner component template, you can use the selectors. The syntax for including the resource with selectors is:
<div data-sly-resource="${ 'inner' # resourceType='/projectname/components/inner', selectors='mySelectorName'}"></div>
The syntax to check the selectors in the inner component is:
${'mySelectorName' in request.requestPathInfo.selectorString}"
or
${'mySelectorName' == request.requestPathInfo.selectorString}"

Parameter and view naming collisions in Play/Scala templates

I am new to Play Framework and still trying to wrap my head around some things with the new Scala template engine.
Let's say I have the following package structure:
app/
app/controllers/Items.scala
app/models/Item.scala
app/views/layouts/page.scala.html
app/views/item/show.scala.html
app/views/item/details.scala.html //partial
And this is my item/show template:
#(item: Item, form: Form[Item])(implicit flash: Flash)
#layout.page() {
#*want to include details partial, wont work due to item param*#
#item.details(item)
}
Since including another template (e.g. including item/details above) is the exact same syntax as accessing a template parameter (e.g. item above), obviously this existing naming convention won't work without something changing.
I know I can rename my "app.views.item" package to "app.views.items", and rely on singular/plural forms to differentiate the view from the param name, but this does not seem like a very straightforward solution. Also what if I really want the parameter name to be the same as the view package?
One idea I have is to prepend all my views with an extra top level package:
app/views/views/item/details.scala.html
So the include syntax would be #views.item.details(), but again this is obviously a hack.
What is a good way to avoid this issue? How can I better organize my code to avoid such naming collisions?
Most other template engines use operations like "include" or "render" to specify a partial include. I don't mean to offend anyone here, but is the Play Scala template engine syntax so terse that it actually dictates the organization of code?
3 solutions:
First
Typpicaly for partial templates you should use tags as described in the docs, where app/views/tags folder is a base:
file: app/views/tags/product.scala.html
in the templates (no initial import required in the parent view full syntax will allow you to avoid name-clash: #tags.packageName.tagName()):
<div id="container">
#tags.product(item)
</div>
Of course in your case you can also use packages in the base folder
file: app/views/tags/item/product.scala.html
<div id="container">
#tags.item.product(item)
</div>
I'm pretty sure that'll solve your problem.
Second
To avoid clash without changing package's name you can just rename the item in your view, also I recommend do not use a form name for the Form[T] as it can conflict with helpers:
#(existingItem: Item, existingItemForm: Form[Item])(implicit flash: Flash)
#layout.page() {
#item.details(existingItem)
}
Third
If you'll fill your Form[Item] before passing to the view with given Item object, you don't need to pass both, as most probably you can get data from the form:
#(itemForm: Form[Item])(implicit flash: Flash)
#layout.page() {
<div>Name of item is: #itemForm("name").value (this is a replacemnet for ##existingItem.name </div>
#item.details(itemForm)
}
Of course in you product.scala.html you'll need to change the #(item: Item) param to #(itemForm: Form[Item])