Fetching Properties From Dialogs

One of CQ’s strongest assets is its ability to create and reuse custom components.  A component’s reusability depends on how flexible and configurable it can be made.  CQ is unlike other component-based frameworks like Adobe Flex because properties or options cannot be passed in in, say, places like the cq:include tag.  Instead, CQ properties and options are configured on pages via dialog boxes.  Here, we will discuss how to retrieve component properties set by these dialog boxes.

If you’re just looking for quick code examples, here are snippets to fetch properties from within a component containing them, and from outside a component.

Step 1: Create a component.  My example will be called “myComponent”

make_component

Step 2: Create a dialog node with some properties.  For convenience, I’ll just be copying mine from an arbitrary sample component packaged with AEM.

dialog_node

Copy the node /apps/geometrixx/components/lead/dialog Into your myComponent folder.  Notice it comes with two items, title and text.  Notice the following properties of the “title” node:

dialog_properties

A more detailed description of how dialogs work is outside the scope of this text, but for now we’ll focus on the “name” property and the “xtype” property.  Widget xtypes define, in part, how a property is stored.  The xtypes of textfield and textarea, which are used in our example, happen to both store their data as java String types.  the name property defines the variable name under which the property is stored.  In this case “jcr:title”.

Step 3: Create an instance of the component within a page.

This can be accomplished via drag + drop, or hard-coding into another component (like a page component) with an include tag:

include_component

<cq:include path="myComponent" resourceType="matelli/components/content/myComponent" />

Tip: component properties cannot be set dynamically the way other platforms, like mxml, allow.

include_component_not_mxml

AEM components do not work like the image above.  The title property must be modified by visiting the page displaying this component and adding text within the dialog box.  (Note: exceptions outstanding, but not covered in this text).

Step 4: Add some text to the title property.

edit_my_component1

Be sure you’re logged into an author environment with a permissioned user (e.g. admin/admin)
Open a page containing your component
Make sure the component is being viewed in edit mode (indicated by the highlighted pencil icon on the sidekick)
Double click on the component.  Tip: the component needs something inside of it.  When hovering over that something, a blue box will appear.

edit_my_component2

Enter some text
Click OK

Step 5: Confirm data is persisted
To view data, CRXDE Lite will work, but CRXDE Explorer is better.

view_component_property

Visit the content and page node where an instance of your component has been created.  It will be under /content/(page name)/jcr:content/myComponent.

The property that we entered was for the title, which we was given the name “jcr:title”.  It should have our data.  The other property that we left blank, named “jcr:text”, has no entry at all.  Note that without a user modifying a dialog box, component properties will have no entry.

Thanks to Sling’s RESTful model, we can view that property directly in a browser by visiting the path listed above.

http://localhost:4502/content/myPage/jcr:content/myComponent/jcr:title

But this will only work with certain property types, and is not the best way to retrieve data from within components.

Step 6: Fetch properties from within a component

Within myComponent.jsp, properties can be retrieved with a call to properties.get().

String title = properties.get("jcr:title", "default title");

Full code:

The first parameter in our properties.get call is the property name.  The second call is a default in case the property doesn’t exist.  Tip: the variable “null” will not work as a second parameter.  In order to retrieve nulls for nonexistent properties, you must specify the class type instead:

String title = properties.get("jcr:title", String.class);

Step 7: Fetch properties in another component

Unfortunately, the convenient properties.get method will only work within a component when extracting its own properties.  In order to get another component’s properties, first we’ll need a node reference to an instance of it.

Option 1

The most direct way is with a hardcoded reference to the object, and use of the resourceResolver class:

String componentPath = "/content/myPage/jcr:content/myComponent"; //path to component
Node node = resourceResolver.getResource(componentPath).adaptTo(Node.class);

Note that we must reference a created instance of the component, not the component itself.  For instance, this will not work:

String componentPath = "/apps/matelli/components/content/myComponent";

The above will not work because properties are not stored on the component itself, but rather a content node whose sling:resourceType points to that component.

Option 2

There are risks to hardcoding that component path.  If the component doesn’t exist, for instance, we’ll get an error while trying to convert it to a node.  We can add some code to work around that if we want:

Resource myResource = resourceResolver.getResource(componentPath);
String title = "", text= "";
if (!Resource.RESOURCE_TYPE_NON_EXISTING.equals(myResource.getResourceType())) {
Node node = myResource.adaptTo(Node.class);
title = node.getProperty("jcr:title").getString();
text= node.getProperty("jcr:text").getString();
}

Option 3

We could also be a more descriptive of our componentPath reference, and use a path relative to a page.

Page myPage = currentPage; //reference to whatever page contains the component";
String componentPath = myPage.getPath() + "/jcr:content/myComponent"; //path to component

Note that unless the component is embedded into the page via a cq:include block, we will want to combine this with the above option and check for the existence of the resource.

Option 4

The Page class has a method for retrieving nodes within “jcr:content” that’s a little cleaner:

Node node = myPage.getContentResource("myComponent").adaptTo(Node.class);

Again, developers may want to combine this method with the ones above that check for a resource’s existence before adapting it to a Node.

Now that we have a node, we can extract properties from that node.

String title = node.getProperty("jcr:title").getString();

Unfortunately, there’s no easy way to specify a property type or default value.  To get other property types, you can use the Property api and fetch other types of data off the Value object.

Calendar date = node.getProperty("myDateProperty").getValue().getDate();

Tip: There’s also a convenience class to help with type extraction of other natives: PropertiesUtil

<%@page import="org.apache.sling.commons.osgi.PropertiesUtil" %>
<% Boolean myProperty = PropertiesUtil.toBoolean(context.getProperties().get("myproperty"), false); %>

However we convert a property, if it does not first exist, we will still get an error.  Therefore, we should check with the hasProperty method first.  All together, it would look like this:

String title = node.hasProperty("jcr:title") ? PropertiesUtil.toString(node.getProperty("jcr:title"), "default title") : "default title";

Here is the full code, with earlier options commented out:

Summary

AEM makes storing and fetching properties relatively easy, although its done differently than some other systems. Properties can be fetched from anywhere, but its easiest from the component itself.

11 thoughts on “Fetching Properties From Dialogs

    1. Nick Matelli Post author

      Thanks so much Praveen. I’ve been focused on other technologies for the last few months, but I do have a dozens of backlogged CQ articles and examples that I’d love to post when I get a chance! If you’d like to help contribute by creating content polished enough to publish, I’d be happy to share all my notes and code snippets.

      Reply
  1. Niranjan

    Hi Nick,

    Nice explanation!!
    I will be fine to contribute through the content which are yet to be published.

    Thanks & Regards,
    Niranjan

    Reply
  2. bala

    Nick – article is simple and awesome . thanks very much for way of explanation . keep it up , please post more articles like this .

    Reply
    1. Nick Matelli Post author

      While there’s the ability to upload images directly into dialogs, I’ve typically let the DAM manage assets. The dialogs are then used to store and retrieve the image name and path. You can then inject that into an tag to display images.

      If you upload and retrieve the image itself as a byte array or something, that’s a more involved process. You’d probably want a custom control there that does your data manipulation too.

      Reply

Leave a Reply to Chiru Cancel reply

Your email address will not be published. Required fields are marked *