Are there requestScope variables in Sightly?
Asked Answered
H

2

7

In JSTL you can set variables in on component that are available to all other components after it in the same request. In AEM using sightly is there an equivalent way to pass data between components ?

(the use case we are looking at is where we want one component to know when it's included via another component, rather than dragged into a parsys).

Haldis answered 21/8, 2014 at 16:8 Comment(0)
M
10

Assuming that with "requestScope" you mean request attributes, which are variables that are scoped to the request.

Setting request attributes is easily possible with Sightly's Use-API. This allows for instance to cache objects that are expensive to retrieve and that are accessed by multiple components of the same request.

What Sightly intentionally makes complicated is to set request attributes right before including a component and to remove them again right after, like the following JSP example:

<% request.setAttribute("myAttribute", someContextualInfo); %>
<cq:include path="innerComponent"/>
<% request.removeAttribute("myAttribute") %>

The reason why we don't want to encourage doing this, is that it isn't a clean pattern: it basically consists in using global variables as a way to communicate between resources... Global variables aren't exactly a best practice, even if you remove them again afterwards.

Try to see if following patterns wouldn't fit better to your needs:

1. Add Selectors

You can pass a dot-separated list of Sling selectors to the components included:

<div data-sly-resource="${'innerComponent' @ addSelectors='foo.bar'}"></div>

The myComponent component can then for instance contain a foo.html, a bar.html, and a foo/bar.html template that would render the different combinations of selectors. But you can also act differently based on the selectors by programmatically accessing them through the RequestPathInfo.

The selectors method has the benefit that you can call your component's content node with various desired selector(s) to choose what rendition of the node you wish:

http://localhost:4502/content/my/content/node.foo.bar.html

One thing to be aware though about this approach, is that if you use selectors with a (theoretically) unbounded set of values, you will see subtle performance problems at first and then eventually blow out the script resolver cache. Selectors should only be used with a (relatively small) bounded set of values.

2. Walking Up

In case you only want to pass a context to some components depending on the parent component that includes it, then it is better to turn the problem upside down and on the child component to walk up the tree of parent nodes and act accordingly.

Imagine for instance that you'd like to add a CSS class to a listItem component based on the parent component that used it in order to add something like the list-item-<parent-component-name> class to the rendition of the listItem:

<li class="list-item list-item-user">User Name</li>

In JSP it is tempting to solve it as follows:

<% request.setAttribute("parentClassName", "user"); %>
<cq:include path="list-item"/>
<% request.removeAttribute("parentClassName") %>

But this is actually not necessary as the child component could check what it's parent component is and figure out by itself what the appropriate value of the parentClassName should be. The benefit is then that that child component could be called directly (for e.g. through AJAX to update the user list) and still render correctly.

3. Use-API

Now if the above two patterns don't correspond to what you need, then you might have not other way than to use request attributes. To do so, you can follow the method described on that other answer. But try to limit that practice as much as possible.

Ministry answered 22/8, 2014 at 12:54 Comment(6)
Hi Gabriel - thanks, great answer. When we implement this it works perfectly, except when doing inline editing. When the component refreshes (editor finishes) we're calling do update but it doesn't pass the selector back in which means the selector adjusted behaviour is lost. Do we need to add the selector to the editable in some way?Haldis
You can define for this component that the whole page should be reloaded after it gets edited, that way it is loaded correctly again with the selector. Do do so, you need a cq:listener configuration on your component with the property afteredit="REFRESH_PAGE". For a similar example, you can have a look at the configuration of the foundation parsys: /libs/foundation/components/parsys/colctrl/cq:editConfig/cq:listeners.Ministry
I've been working with Sightly full time for 7 months and keep coming across instances where this feature would be of significant benefit. E.g. we have an 'image' component with many editable properties, and want to automatically include an instance of this component in another component, setting some default values such as image width.Anaplastic
e.g. as also described here: #25405363Anaplastic
thanks! e.g. <div data-sly-resource="${ @path='image', resourceType='customapp/components/image', forceImageWidth=400, imageWidthEditable=false}"></div>Anaplastic
Let us continue this discussion in chat.Anaplastic
R
2

Yes

Request scoped variables are available from "Scripting Sightly Engine 1.0.20" onwards. This is available likely after AEM version 6.3.

However the bundle can be installed manually as it is open-source. I haven't tested this yet.

Please refer: https://issues.apache.org/jira/browse/SLING-5812

Risa answered 15/12, 2016 at 10:23 Comment(1)
It's available - see docs.adobe.com/docs/en/htl/docs/…Histidine

© 2022 - 2024 — McMap. All rights reserved.