12
votes

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

4

4 Answers

9
votes

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.

5
votes

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.

0
votes

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

0
votes

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}"