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.

en page in edit mode 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 decalres the server-side example.js file as the source and passes a prameter 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

Adobe Experience Manager | CRXDE Lite | /content/we-retail/us/en/about-us/jcr:content

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.

AEM JavaScript Use-API String Multi JSON

comments powered by Disqus