ADOBE EXPERIENCE MANAGER (AEM)
AEM JavaScript Use-API ResourceUtils
ResourceUtils examples using an AEM Maven project and the We.Retail sample to show how to pass data from the HTL to server-side JavaScript, and use the /libs/wcm/foundation/components/utils/ResourceUtils.js
to access properties from jcr:content
.
For this first example, we’re using the AEM Maven Project Archetype 23 which already contains proxies to the core components, a content page template and a base page with some content.
To inspect the resource object, let’s extend the core container component and add an info.js
file to it.
Using CRXDE, copy container.html
from /apps/core/wcm/components/container/v1/container/
and paste into /apps/myproject/components/container/
.
Create an info.js
Use-API JavaScript in the /apps/myproject/components/container
folder. e.g.,
info.js
"use strict";
use( function() {
log.info('### ' + resource);
});
Edit the end of the /apps/myproject/components/container/container.html
HTL template to use the info.js
. e.g.,
container.html
...
<sly data-sly-use.info="info.js" />
</sly>
Load the base page in “View as Published” mode using the wcmmode=disabled
querystring. e.g., http://localhost:4502/content/myproject/us/en.html?wcmmode=disabled
In the crx-quickstart/logs/error.log
, read the log.info('### ' + resource)
output from our info.js
. Since the container is used on both the en
page and respective content page template, there is a log entry being written for each instance. e.g.,
error.log
07.03.2020 11:40:56.130 *INFO* [127.0.0.1 [1583599256071] GET /content/myproject/us/en.html HTTP/1.1] apps.myproject.components.container.container$html ### /content/experience-fragments/myproject/us/en/site/header/master/jcr:content/root
07.03.2020 11:40:56.150 *INFO* [127.0.0.1 [1583599256071] GET /content/myproject/us/en.html HTTP/1.1] apps.myproject.components.container.container$html ### /content/myproject/us/en/jcr:content/root/container/container
07.03.2020 11:40:56.150 *INFO* [127.0.0.1 [1583599256071] GET /content/myproject/us/en.html HTTP/1.1] apps.myproject.components.container.container$html ### /conf/myproject/settings/wcm/templates/page-content/structure/jcr:content/root/container
07.03.2020 11:40:56.157 *INFO* [127.0.0.1 [1583599256071] GET /content/myproject/us/en.html HTTP/1.1] apps.myproject.components.container.container$html ### /content/experience-fragments/myproject/us/en/site/footer/master/jcr:content/root
07.03.2020 11:40:56.157 *INFO* [127.0.0.1 [1583599256071] GET /content/myproject/us/en.html HTTP/1.1] apps.myproject.components.container.container$html ### /conf/myproject/settings/wcm/templates/page-content/structure/jcr:content/root
For more info on logs, see the Debugging / Logging section from this series.
This shows us what are resource
value is. Now let’s use this value with ResourceUtils.getResource
. Replace the contents of container/info.js
as follows.
info.js
"use strict";
use(["/libs/wcm/foundation/components/utils/ResourceUtils.js"], function (ResourceUtils) {
var data = {};
ResourceUtils.getResource(resource + "/helloworld")
.then(function (node) {
var props = node.properties;
data.text = props["text"];
});
return data;
});
This will return the text property value from the helloworld component within the container component.
Update the end of our /apps/myproject/components/container/container.html
template to output the data being returned. The data-sly-test
attribute on the pre
element is testing if the info.text
value exists before it will render itself.
container.html
...
<sly data-sly-use.info="info.js">
<pre data-sly-test="${info.text}">
helloworld text property: ${info.text}
</pre>
</sly>
</sly>
Load the base page in edit mode to see the helloworld text property value being output in the parent container.
localhost:4502/content/myproject/us/en.html
We.Retail Example
For this example we’ll be using crx/de
in author runmode to edit the weretail
app directly on the server. e.g., http://localhost:4502/crx/de
In /apps/weretail/components/structure/page
create a file named example.js
as follows.
"use strict";
use(["/libs/wcm/foundation/components/utils/ResourceUtils.js"], function (ResourceUtils) {
var data = {};
data.key = this.key;
ResourceUtils.getResource("/content/we-retail/us/en/" + this.key + "/jcr:content")
.then(function (node) {
var props = node.properties;
data.title = props["jcr:title"];
});
return data;
});
In the server-side JavaScript file, access the value of parameters using this
, for example this.key
.
Passing Data
With HTL, we can pass data into the server-side JavaScript in the data-sly-use
value as a parameter. For example.
Edit /apps/weretail/components/structure/page/body.html
and add these two sly
elements and a pre
element before the closing div
as follows.
<div class="container">
...
<sly data-sly-test.key="${request.requestParameterMap['key'][0].toString}"/>
<sly data-sly-use.example="${'example.js' @ key=key}"></sly>
<pre>
example.title: ${example.title}
</pre>
</div>
The first sly element sets a variable named key
using the value from the key
query string parameter in the request.
The second sly element, sets a variable name example
using data-sly-use.example
. It declares the server-side example.js
file as the source and passes a parameter named key
into the JavaScript. The key
contains the key
value that was declared in the first sly element.
Using a query string parameter, we can access the jcr:content
for the page node supplied as the key
. To test this, load http://localhost:4502/content/we-retail/us/en.html?key=about-us in a new browser tab. This request has the query string key
parameter set to about-us
. In the example.js
we’re using the key parameter value to lookup the content for the about-us
node.
Scroll down the page and note the values output in the pre
element we added to test the results returned by the Use-API JavaScript.
If we inspect /libs/wcm/foundation/components/utils/ResourceUtils.js
in CRXDE Lite, you can see all of the available methods and logging that is taking place.
For example, the getResource
method.
/**
* Resolves a resource
*
* @returns promise as returned by the granite.resource.resolve or undefined if
* the 'granite' cross-platform API is not available
*/
ResourceUtils.getResource = function (resourcePath) {
var resolvedResource = undefined;
if (typeof granite != "undefined") {
// resolve based on cross platform API
log.debug("Found 'granite' cross-platform namespace, using it to resolve " + resourcePath + " path");
resolvedResource = granite.resource.resolve(resourcePath);
log.debug("Resolved resource " + resourcePath);
} else {
log.error("Can't find 'granite' cross-platform namespace!");
}
return resolvedResource;
}
return ResourceUtils;
Functions
Here is an example of how to use functions in the server-side JavaScript. Suppose you would like to ensure that a property value is title cased when sent to the Sightly (HTL) file? Using a function, we can pass the property value into a function that returns it in title case. Here, we add a function named toTitleCase
in the existing example.js
file we created earlier. We will pass it the jcr:title
property as a str
parameter to be returned Title cased. e.g.,
"use strict";
use(["/libs/wcm/foundation/components/utils/ResourceUtils.js"], function (ResourceUtils) {
var data = {};
data.key = this.key;
ResourceUtils.getResource("/content/we-retail/us/en/" + this.key + "/jcr:content")
.then(function (node) {
var props = node.properties;
data.title = toTitleCase(props["jcr:title"]);
});
function toTitleCase(str) {
var _str = new String(str);
return _str.replace(/(^|\s)[a-z]/g, function(chr){ return chr.toUpperCase() });
}
return data;
});
To test the new function, using crx/de
select the /content/we-retail/us/en/about-us/jcr:content
resource and edit the jcr:title
property value by updating with a lower case string. e.g., About Us test
Save the changes in /crx/de
and load / reload http://localhost:4502/content/we-retail/us/en.html?key=about-us. Scroll down to see the jcr:title
rendered in Title case, e.g., example.title: About Us Test
.
Part 1 of 4 in the AEM JavaScript Use-API series.