I currently have a data-sly-list that populates a JS array like this:
var infoWindowContent = [
<div data-sly-use.ed="Foo"
data-sly-list="${ed.allassets}"
data-sly-unwrap>
['<div class="info_content">' +
'<h3>${item.assettitle @ context='unsafe'}</h3> ' +
'<p>${item.assettext @ context='unsafe'} </p>' + '</div>'],
</div>
];
I need to add some logic into this array. If the assetFormat
property is 'text/html' only then I want to print the <p>
tag. If the assetFormat
property is image/png
then I want to print img
tag.
I'm aiming for something like this. Is this possible to achieve?
var infoWindowContent = [
<div data-sly-use.ed="Foo"
data-sly-list="${ed.allassets}"
data-sly-unwrap>
['<div class="info_content">' +
'<h3>${item.assettitle @ context='unsafe'}</h3> ' +
if (assetFormat == "image/png")
'<img src="${item.assetImgLink}</img>'
else if (assetFormat == "text/html")
'<p>${item.assettext @ context='unsafe'}</p>'
+ '</div>'],
</div>
];
To answer your question quickly, yes you can have a condition (with data-sly-test
) in your list as follows:
<div data-sly-list="${ed.allAssets}">
<h3>${item.assettitle @ context='html'}</h3>
<img data-sly-test="${item.assetFormat == 'image/png'}" src="${item.assetImgLink}"/>
<p data-sly-test="${item.assetFormat == 'text/html'}">${item. assetText @ context='html'}"</p>
</div>
But looking at what you're attempting to do, basically rendering that on the client-side rather than on the server, let me get a step back to find a better solution than using Sightly to generate JS code.
A few rules of thumb for writing good Sightly templates:
@context='unsafe'
, unless you filter that string somehow yourself. Each string that is not
escaped or filtered could be used in an XSS attack. This
is the case even if only AEM authors could have entered that string,
because they can be victim of an attack too. To be secure, a system
shouldn't hope for none of their users to get hacked. If you want to allow some HTML, use @context='html'
instead.A good way to pass information to JS is usually to use a data attribute.
<div class="info-window"
data-sly-use.foo="Foo"
data-content="${foo.jsonContent}"></div>
For the markup that was in your JS, I'd rather move that to the client-side JS, so that the corresponding Foo.java logic only builds the JSON content, without any markup inside.
package apps.MYSITE.components.MYCOMPONENT;
import com.adobe.cq.sightly.WCMUsePojo;
import org.apache.sling.commons.json.io.JSONStringer;
import com.adobe.granite.xss.XSSAPI;
public class Foo extends WCMUsePojo {
private JSONStringer content;
@Override
public void activate() throws Exception {
XSSAPI xssAPI = getSlingScriptHelper().getService(XSSAPI.class);
content = new JSONStringer();
content.array();
// Your code here to iterate over all assets
for (int i = 1; i <= 3; i++) {
content
.object()
.key("title")
// Your code here to get the title - notice the filterHTML that protects from harmful HTML
.value(xssAPI.filterHTML("title <span>" + i + "</span>"));
// Your code here to detect the media type
if ("text/html".equals("image/png")) {
content
.key("img")
// Your code here to get the asset URL - notice the getValidHref that protects from harmful URLs
.value(xssAPI.getValidHref("/content/dam/geometrixx/icons/diamond.png?i=" + i));
} else {
content
.key("text")
// Your code here to get the text - notice the filterHTML that protects from harmful HTML
.value(xssAPI.filterHTML("text <span>" + i + "</span>"));
}
content.endObject();
}
content.endArray();
}
public String getJsonContent() {
return content.toString();
}
}
A client-side JS located in a corresponding client library would then pick-up the data attribute and write the corresponding markup. Obviously, avoid inlining that JS into the HTML, or we'd be mixing again things that should be kept separated.
jQuery(function($) {
$('.info-window').each(function () {
var infoWindow = $(this);
var infoWindowHtml = '';
$.each(infoWindow.data('content'), function(i, content) {
infoWindowHtml += '<div class="info_content">';
infoWindowHtml += '<h3>' + content.title + '</h3>';
if (content.img) {
infoWindowHtml += '<img alt="' + content.img + '">';
}
if (content.text) {
infoWindowHtml += '<p>' + content.title + '</p>';
}
infoWindowHtml += '</div>';
});
infoWindow.html(infoWindowHtml);
});
});
That way, we moved the full logic of that info window to the client-side, and if it became more complex, we could use some client-side template system, like Handlebars. The server Java code needs to know nothing of the markup and simply outputs the required JSON data, and the Sightly template takes care of outputting the server-side rendered markup only.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With