Talks about how to build AEM Components using Granite/Coral Resource Types

Article summary

Summary


Discusses how to create an AEM components that use Granite/Coral Resource Types. 

A special thank you to Ratna Kumar Kotla and Navin Kaushal, very helpful AEM community members, for testing this article to ensure it works.

Its great community members like those mentioned here that help the overall AEM community and drives the success of AEM Developers using Adobe Experience Manager.

Update - this artilce was updated to show use of Radio granite types in the Multifield. 

Update - this article was updated to show use of multiple DataSource objects to update multiple Select fields

Update - this article was updated to show use of a Sling Servlet and JSON data to populate a Select field. Thank you Arun Patidar for the code that is used here. 

Digital Marketing Solution(s) Adobe Experience Manager 6.3/6.4
Audience Developer
Required Skills Java, HTML, JavaScript
Version 6.3/6.4

Introduction

When creating components for Adobe Experience Manager (AEM) 6.4, you use Granite/Coral resource types. These resource types are used in the component’s dialog. That is, the UI that makes up the dialog fields and lets an author enter information used by the AEM component.

Many AEM Developers are familiar with Classic UI xtypes based widgets such as text fields, path fields, drop-down fields, and so on. However, when it comes to working with the Touch UI, xtypes are not used. Instead resource types are used to build Touch UI component dialogs. This article helps you become familiar working with Granite/Coral resource types that can be applied in your day to day component development work.

Note:

Granite/Coral resource types are not to display a rendered component in an AEM web page. That is, you do not use them in a clientlibs folder or use them in JS rendered in an AEM page. They are used in the component’s dialog on the Author instance. If you requirement is to place a datepicker on a webpage, you would NOT use the datepicker resource type to render a datepicker. You can use a JQuery plugin to render a calendar. The datepicker resource type is used in the components dialog as illustrated in this article. 

Resource Types used in this article

This article teaches you how to build Experience Manager components by using Granite/Coral data types such as:

  • granite/ui/components/coral/foundation/form/textfield
  • granite/ui/components/coral/foundation/form/textarea
  • granite/ui/components/coral/foundation/form/checkbox
  • granite/ui/components/coral/foundation/form/pathbrowser
  • granite/ui/components/coral/foundation/form/select
  • granite/ui/components/coral/foundation/form/autocomplete
  • granite/ui/components/coral/foundation/form/datepicker
  • granite/ui/components/coral/foundation/form/radio (shown in the Multifield section)
  • granite/ui/components/coral/foundation/form/multifield

Note:

This AEM Community article does not cover using Tabs in your component dialog. To see a working example of using tabs in your component dialog, see Creating an AEM 6.4 HTML Template Language movie component.

Key Takeaways

  • Learn to work with the Granite/Coral resource types on AEM such as granite/ui/components/coral/foundation/form/textfield.
  • Learn to populate Select field with static values using JCR nodes.
  • Learn to populate Select field with dynamic values using Java logic.
  • Learn how to read Granite/Coral resource types by using HTL syntax.
  • Learn how to read Granite/Coral resource types by using a WCMUsePojo class.
  • Learn how to read Granite/Coral resource types by using Sling Models.
  • Learn how to read Granite/Coral resource types located in a Multifield by using Sling models.
  • Learn how to display these values in AEM Components. 
     

Create an Experience Manager project

In the first section of this article, you are going to create an Experience Manager project named Lab2018. This project is used for the remainder of this article. You use this project to create components that use various Granite/Coral resource types.

In this article, you create an Adobe Maven Archetype 11 project that is used as a starting point that contains components, templates, and a Java project that you are going to use in later sections. You are going to use CRXDE lite to build dialogs and modify files such as HTML files. Likewise, you are using to use Eclipse and Maven to build OSGi bundles for the article sections that require them.
 

Create an Experience Manager project using Maven

To create your Experience Manager project:

1. Open the command window.

2. Change the working directory to C:\Adobe.

3. Test Maven by entering the following command: mvn -version. If successful, you will see a message such as:

Maven1
A message displayed by Maven

4. Run the following Maven command:

mvn org.apache.maven.plugins:maven-archetype-plugin:2.4:generate -DarchetypeGroupId=com.adobe.granite.archetypes -DarchetypeArtifactId=aem-project-archetype -DarchetypeVersion=11 -DarchetypeCatalog=https://repo.adobe.com/nexus/content/groups/public/

5. When prompted, specify the following information:

  • groupId – Lab2018
  • artifactId - Lab2018
  • version - <Leave blank>
  • package - com.aem.summit
  • appsFolderName - Lab2018
  • artifactName - Lab2018
  • componentGroupName - Lab2018
  • contentFolderName - Lab2018
  • cssId - Lab2018
  • packageGroup - Lab2018
  • siteName - Lab2018

6. When prompted, specify Y.

7. Once done, you will see a message like:
 

Maven2
Build was successful

8. Change the working directory to Lab2018 and then enter the following command: mvn eclipse: eclipse.
 

Add Java files to the Maven project using Eclipse

To make it easier to work with the Maven generated project, import it into the Eclipse development environment, as shown in the following illustration.

Eclipse
Eclipse Import Project Dialog

Note:

Do not worry about the errors reported in Eclipse. It does not read the POM file where the APIs are resolved. You build the bundle with Maven. Eclipse is used to edit the Java files and the POM file.

To import the project:

1. Start Eclipse.

2. Click File, Import.

3. In the Import dialog, click General, Existing Projects into Workspace.

4. Click Next.

5. Select Root Directory.

6.  Browse to the project that you created by using Maven.

7. Click Finish

 

After you import the project into Eclipse, notice each module is a separate Eclipse project:

  • core - where Java files that are used in OSGi services and sling servlets are located (this is where you work)
  • launcher - where additional Java files are located
  • tests - Java files for tests like JUNIT tests
  • apps - content under /apps
  • content - content under /content

By default, the Archetype 11 project creates many Java files that you can use as a starting point in your project (these Java files are located under core). The following illustration shows the Java packages.

 

PEx
Default files

Note:

These default files are explained in this article: Creating an Adobe Experience Manager 6.3 Project using Adobe Maven Archetype 11.  

Import the Lab2018 project into Experience Manager

Import the Lab2018 project into Experience Manager by using the following Maven command:

mvn -PautoInstallPackage install

After you successfully import the project into Experience Manager, you can view the project files in CRXDE lite under /apps/Lab2018.

crxde
The project imported into AEM

In the previous illustration, the red arrow is referencing the location of the default components under /apps/Lab2018/components/content.

You can also view Lab2018 files at the following locations:

  • /content/dam/Lab2018 (where digital assets are stored for this project)
  • /content/Lab2018 (where the web pages are located)
  • /etc/designs/Lab2018 (where the CSS and JS files are located)

View the Default page

You can view the default page for this project by performing these tasks:

1. Click the Adobe Experience Manager icon in the upper left corner.

2. Click the Navigation Icon.

3. Click Sites, Lab2018, English.

4. Click the Edit icon in the toolbar.

 

Pic909
Edit the Lab2018 page

This page is the one you are going to use for this reminder of this development article. Once you see the page, delete all the default components on this page. To delete a component, hover your mouse over the component and then click the Delete icon that appears.
 

Page
Delete the default components

Once done, the page resembles the following illustration.

Page2
The default page without components

Create a HTL component

In this section, you are going to build a basic AEM component that renders values that an author enters in a dialog. The component has a dialog that has these sling resource types:

granite/ui/components/coral/foundation/container - defines a container for the dialog
granite/ui/components/coral/foundation/fixedcolumns - defines fixed columns
granite/ui/components/coral/foundation/form/textfield - defines a text field that lets authors enter data
granite/ui/components/coral/foundation/form/textarea - defines a text area field that lets author more data than a text field

This component uses HTL syntax to read the values that an author specifies in the dialog. The following illustration shows the dialog that you develop in this section.

dialog
A component dialog

In this dialog, the Heading Text field is a textfield and Description is a textarea.

Section Package

Download

Create the Experience Manager component

To create the Experience Manager component, perform these tasks using CRXDE Lite:

1. Right click on /apps/Lab2018/components/content and then select New, Component.

2. Enter the following information into the Create Component dialog box:

  • Label: The name of the component to create. Enter firstcomponent.
  • Title: The title that is assigned to the component. Enter firstcomponent.
  • Description: The description that is assigned to the component. Enter any value you want. 
  • Super Resource Type: Enter foundation/components/parbase.
  • Group: The group in the side rail where the component appears. Enter Lab2018

3. Click Ok.

4. Change the extension from .jsp to .html.


Build the Dialog using CRXDE lite

An Experience Manager component dialog is a structure of JCR nodes. The dialog nodes are typically placed under a component. In this article, you are going to build the dialog nodes at this JCR location:

/apps/Lab2018/components/content/firstcomponent

dialogNodes
JCR nodes that make up the dialog

To build the dialog, perform these tasks:

1. Select /apps/Lab2018/components/content/firstcomponent.

2. Right click and select Create, Create Node.

3. Enter the following values:

  • Name: cq:dialog
  • Type: nt:unstructured

4. Add the following properties to the cq:dialog node.

  •  helppath (String) - en/cq/current/wcm/default_components.html#Carousel
  • jcr:title (String) - Hero Text
  • sling:resourceType (String) - cq/gui/components/authoring/dialog

5. Click on the following node: /apps/Lab2018/components/content/firstcomponent/cq:dialog.

6. Right click and select Create, Create Node. Enter the following values:

  • Name: content
  • Type: nt:unstructured

7. Add the following property to the content node.

  • sling:resourceType (String) - granite/ui/components/coral/foundation/container

8. Click on the following node: /apps/myHTL63/components/content/helloworld/cq:dialog/content.

9. Right click and select Create, Create Node. Enter the following values:

  • Name: layout
  • Type: nt:unstructured

10. Add the following properties to the layout node.

  • sling:resourceType (String) - granite/ui/components/coral/foundation/tabs
  • type (String) -nav

11. Click on the following node: /apps/Lab2018/components/content/firstcomponent/cq:dialog/content.

12. Right click and select Create, Create Node. Enter the following values:

  • Name: items
  • Type: nt:unstructured

13. Click on the following node: /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items.

14. Right click and select Create, Create Node. Enter the following values:

  • Name: herotext
  • Type: nt:unstructured

15. Add the following properties to the herotext node (this node represents the tab).

  • jcr:title (String) - Hero Text Properties
  • sling:resourceType (String) - granite/ui/components/foundation/section

16. Click on the following node: /apps/Lab2018/components/content/firstcomponent/content/items/herotext.

17. Right click and select Create, Create Node. Enter the following values:

  • Name: layout
  • Type: nt:unstructured

18. Add the following property to the layout node.

  • sling:resourceType (String) - granite/ui/components/coral/foundation/fixedcolumns

19. Click on the following node: /apps/Lab2018/components/content/firstcomponent /cq:dialog/content/items/herotext.

20. Right click and select Create, Create Node. Enter the following values:

  • Name: items
  • Type: nt:unstructured

21. Click on the following node: /apps/Lab2018/components/content/firstcomponent /cq:dialog/content/items/herotext/items.

22. Right click and select Create, Create Node. Enter the following values:

  • Name: column
  • Type: nt:unstructured

23. Click on the following node: /apps/Lab2018/components/content/firstcomponent /cq:dialog/content/items/herotext/items/column.

24. Add the following property to the column node.

sling:resourceType (String) - granite/ui/components/coral/foundation/container

25. Click on the following node: /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/columns.

26. Right click and select Create, Create Node. Enter the following values:

  • Name: items
  • Type: nt:unstructured

27. Click on the following node: /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items.

28. Right click and select Create, Create Node. Enter the following values:

  • Name: headingText
  • Type: nt:unstructured

29. Click on the following node: /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items/headingText.

30. Add the following properties to the headingText node (this node represents the Heading Text input control on the dialog. See the illustration at the start of this article.)

  • fieldLabel (String) - Heading Text
  • name (String) - ./heading
  • sling:resourceType (String) - granite/ui/components/coral/foundation/form/textfield

31. Click on the following node: /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items.

32. Right click and select Create, Create Node. Enter the following values:

  • Name: description
  • Type: nt:unstructured

33. Click on the following node: /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/

items/column/items/description.

34. Add the following property to the description node (this node represents the Description input field on the dialog. See the illustration at the start of this article.)

  • fieldLabel (String) - Description
  • name (String) -./description
  • sling:resourceType (String) - granite/ui/components/coral/foundation/form/textarea

Notice the names of the headingText and description nodes: heading and description. These values are used in the HTL logic to display the values

Add HTL code to the firstcomponent

After you build the component and the component dialog, where you specify the Granite/Coral resource types, you are ready to add code to the component at this JCR location:

/apps/Lab2018/components/content/firstcomponent/firstcomponent.html

Add the following code to this component.

<div>
<p>This is your HTML Template Language component:</p>
      <h1>${properties.heading}</h1>
       <p>${properties.description}</p>    
</div>

In this example, notice how the dialog values are rendered in the HTL component.

  • ${properties.heading} writes out the value that an author enters into the textfield. 
  • ${properties.description} writes out the value that an author enters into the textarea field.
     

View the output of the HTL component

You can view the output of the component by opening the Lab2018, English as discussed in Section 1.

Page3
The default page

Once you drag the component onto the page, open the dialog and enter values. Click the checkmark icon and you will see the values are rendered on the web page, as shown here.

Page4
The component displayed in the AEM web page

Perform these tasks:

1. Change the mode to Edit mode.
2. From the side rail on the left, click Components.
3. You should see the components with Group Lab2018.
4. Drag the firstcomponent from the side rail onto the page.
5. Edit the component and fill in the two fields.
6. Click the Check mark in the dialog.
7. Now the values show up in the web page.

Add additional resource types to your component

In this section, you are going to add these additional resource types to the component dialog:

  • granite/ui/components/coral/foundation/form/pathbrowser
  • granite/ui/components/coral/foundation/form/datepicker
  • granite/ui/components/coral/foundation/form/checkbox
  • granite/ui/components/coral/foundation/form/select.

These represent common resource types that are typically located in AEM component dialog. For a complete listing of Granite types, see Granite Types.

The following illustration shows the JCR nodes once you are done this section.
 

dialogNodes2
The dialog with additional resource types

Download

pathbrower

A pathbrower lets an author select a node in the AEM JCR. When setting a pathbrower, you can specify the rootpath that represents the default JCR location that is displayed when the pathbrowser is opened. The following illustration represents a pathbrowser.

Pathbr
A pathbrower resource type

Datepicker

The Date Picker is an input component where an author can select a date. The following illustration represents a date picker.

datepick
A DatePicker

Checkbox

A checkbox component lets an author check an item in the component dialog. The following illustration shows a checkbox.

checkbox
A checkbox

Select

A Select resource type is a drop-down field that lets an author select a value from a list. You can set the values using child nodes. The following illustration shows the Select resource type.

Select
A Select resource type

Add resource types to the dialog

In this section, you are going to add additional resource types to the component’s dialog.

Add the pathbrowser field to the dialog

You can add a pathbrowser resource type to the component dialog by adding additional nodes to the dialog created in the previous section. Perform these tasks:

1 Select the node at:
/apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items.

2. Right click and select Create, Create Node. Enter the following values:

  • Name: path
  • Type: nt:unstructured

3. Click on the following node: /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items/path.

4. Add the following properties to the path node:

  • fieldDescription (String) - Select a Path
  • fieldLabel (String) - Path
  • name (String) - ./path (you reference this value to read this value of this component field) 
  • rootpath (String) - /content
  • sling:resourceType (String) - granite/ui/components/coral/foundation/form/pathbrowser

 

Add the datepicker field to the dialog

You can add a datepicker resource type to the component dialog by adding additional nodes to the dialog created in the previous section. Perform these tasks:

1 Select the node at:
/apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items.

2. Right click and select Create, Create Node. Enter the following values:

  • Name: startDate
  • Type: nt:unstructured

3. Click on the following node:  /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items/ startDate.

4. Add the following properties to the startDate node:

  • displayedFormat (String) - YYYY-MM-DD HH:mm
  • fieldLabel (String) - Start Date
  • name (String) - ./startdate (you reference this value to read this value of this component field) 
  • class (String) - field
  • sling:resourceType (String) - granite/ui/components/coral/foundation/form/datepicker
  • type (String) – datetime
     

Add the checkbox field to the dialog

You can add a checkbox resource type to the component dialog by adding additional nodes to the dialog created in the previous section. Perform these tasks:

1 Select the node at:
/apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items.

2. Right click and select Create, Create Node. Enter the following values:

  • Name: show
  • Type: nt:unstructured

3. Click on the following node: /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items/ show.

4. Add the following properties to the show node:

  • text (String) - Show?
  • value (String) – yes (the submitted value when the checkbox is checked) 
  • name (String) - ./show (you reference this value to read this value of this component field)
  • sling:resourceType (String) - granite/ui/components/coral/foundation/form/checkbox
     

Add the Select field to the dialog

You can add a Select resource type to the component dialog by adding additional nodes to the dialog created in the previous section.

Select2
Select dialog nodes

Perform these tasks:

1 Select the node at:
/apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items.

2. Right click and select Create, Create Node. Enter the following values:

  • Name: type
  • Type: nt:unstructured

3. Click on the following node: /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items/ type.

4. Add the following properties to the type node:

  • fieldDescription (String) - Select Size
  • fieldLabel (String) - Size
  • name (String) - ./size (you reference this value to read this value of this component field) 
  • sling:resourceType (String) - granite/ui/components/coral/foundation/form/select

5. Select the node at:
/apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items/type.

6. Right click and select Create, Create Node. Enter the following values:

  • Name: items
  • Type: nt:unstructured

7. Select the node at:
/apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items/type/items.

8. Right click and select Create, Create Node. Enter the following values:

  • Name: small
  • Type: nt:unstructured

9. Add the following properties to the small node:

  • text (String) - small
  • value (String) – small

10. Click on the following node: /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items/ type.

11. Right click and select Create, Create Node. Enter the following values:

  • Name: medium
  • Type: nt:unstructured

12 Add the following properties to the medium node:

  • text (String) - medium
  • value (String) – medium

13. Click on the following node: /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items/ type.

14. Right click and select Create, Create Node. Enter the following values:

  • Name: large
  • Type: nt:unstructured

15 Add the following properties to the large node:

  • text (String) - large
  • value (String) - large
     

Modify the component HTML to read the new values

Modify the firstcomponent.html file to display the resource types added to the component dialog. For each new resource type added to the component dialog, add application logic to read the fields.
Replace the code in this HTML file with the following code.
 

<div>
<p>This is your AEM HTML Template Language component:</p>
      <h1>${properties.heading}</h1>
       <p>${properties.description}</p>
       <p>The following values are the resource types added to the dialog</p>
       <p><b>Selected Path value:</b> ${properties.path}</p>

       <p>
            <b>Date:</b> 
                  ${'yyyy-MM-dd HH:mm:ss.SSSXXX' @ format=properties.startdate, timezone='UTC'}
        </p>
        <p>
            <b>Size:</b> ${properties.size}
        </p>
        <p>
            <b>Checkbox:</b> ${properties.show}
        </p>
</div>

As the startdate is a node based on a Date data type, notice the way the date value is displayed in HTL syntax.


${'yyyy-MM-dd HH:mm:ss.SSSXXX' @ format= properties.startDate, timezone='UTC'}
 

Test the modified component dialog

Edit the dialog and hover over the component with your mouse and click the Configure icon.

Dialog1
Edit the dialog

Enter values into the dialog, as shown in this illustration.

Dialog2
Enter values into the dialog

When you click the Check Mark icon, you will see the values rendered in the web page, as shown in this illustration.

Dialog3
The dialog values displayed in the AEM web page

Understanding where dialog data is stored

When you re-open the component dialog, you will see that data is displayed in the dialog. Experience Manager stores dialog data under the corresponding page under /content. In this section, notice the following path:


/content/Lab2018/en/jcr:content/par/firstcomponent

As you can see in this illustration, the dialog values are stored as properties on the firstcomponent node under par.
 

crxde2
dialog values stored in the JCR

If you ever have an issue of a value not showing up in a dialog, check the properties of the corresponding node under /par.

Use WCMUSEPOJO with the component

Up to this point in this article, you created a component, built a component dialog that contains various sling resource types and created HTL application logic that rendered the values in the web page. In this section, you are going to use Eclipse to develop Java classes to work with the HTL component and learn how to read the dialog values by using Java.

You may be wondering why use Java if you can read the values in HTL itself. The main reason is sometimes you need to perform application logic using the values. For example, you may need to invoke a 3rd party service using the dialog values, parse the values and so on. That is, you may need to perform additional application logic on the data that cannot be performed by using HTL. By including Java into your component, you are opening a lot of possibilities in terms of functionality.

To create a Java backend for a HTL component, you can use either WCMUsePojo or Sling Models (this article covers both ways.) To use the WCMUsePojo API,  you create a class that extends WCMUsePojo.

The next step is to add these Java files to the com.aem.summit.core package:

  • HeroTextComponent 
  • HeroTextBean 

The HeroTextBean is a Java bean that has class members to match the fields specified in the component's dialog. In this example, it has these string class members:

  • headingText – stores the value entered in the heading field
  • description – stores the value entered in the description field
  • path – stores the value entered in the path field
  • startDate – stores the value entered in the date field
  • show – stores the value entered in the check field
  • type – stores the value selected from the select field 

The HeroTextComponent class is the Java side of the HTL component and extends WCMUsePojo, which is an abstract class that implements the Use interface.
 

Download

Add Java classes to your Lab2018 project

Add two Java classes to Eclipse by performing these tasks.

1. Open Eclipse to Lab2018.

2. In the Package Explorer, click on the com.aem.summit.core package.

3. Click and Select New, Class.

4. Name the Class HeroTextBean.

5. Repeat steps 2-4 for the HeroTextComponent class.

Once done, your project resembles the following illustration.
 

eclipse1
Eclipse Development Environment

Add Java logic to the HeroTextBean class

The HeroTextBean defines class members and contains getter and setter methods. Add the following Java code to the HeroTextBean class in Eclipse.

package com.aem.summit.core;
/**
 * The Class HeroTextBean.
 */
public class HeroTextBean {
       
    /** The heading text. */
    private String headingText;
       
    /** The description. */
    private String description;
    
    /** Stores Path information */
    private String path ; 
    
    /** Stores Date information */
    private String startDate ; 
        
    /** Stores Checkbox information */
    private String show ; 
       
    /** Stores Select  information */
    private String type; 
            
    public String getType() {
        return this.type;
    }
    /**
     * @param path the path to set
     */
    public void setType(String type) {
        this.type = type;
    }
            
    public String getShow() {
        return this.show;
    }
    /**
     * @param path the path to set
     */
    public void setShow(String show) {
        this.show = show;
    }
      
    public String getDate() {
        return this.startDate;
    }
    /**
     * @param path the path to set
     */
    public void setDate(String date) {
        this.startDate = date;
    }
   public String getPath() {
        return this.path;
    }
    /**
     * @param path the path to set
     */
    public void setPath(String path) {
        this.path = path;
    }
    
    /**
     * @return the headingText
     */
      
    public String getHeadingText() {
        return headingText;
    }
    /**
     * @param headingText the headingText to set
     */
    public void setHeadingText(String headingText) {
        this.headingText = headingText;
    }
    /**
     * @return the description
     */
    public String getDescription() {
        return description;
    }
    /**
     * @param description the description to set
     */
    public void setDescription(String description) {
        this.description = description;
    }
   
}

Add Java logic to the HeroTextComponent class

The HeroTextComponent extends WCMUsePojo class. Add the following Java code to the HeroTextComponent class in Eclipse.

package com.aem.summit.core;

import com.adobe.cq.sightly.WCMUsePojo;
import com.aem.summit.core.HeroTextBean;
  
public class HeroTextComponent
extends WCMUsePojo
{
  
     /** The hero text bean. */
    private HeroTextBean heroTextBean = null;
       
    @Override
    public void activate() throws Exception {
           
         heroTextBean = new HeroTextBean();
               
        //Get the values that the author entered into the AEM dialog
        String heading = getProperties().get("heading", "");
        String description = getProperties().get("description","");
        String path = getProperties().get("path","");
        String date = getProperties().get("startdate","");
        String show = getProperties().get("show","");
        String type = getProperties().get("size","");
     
	     //Set the Bean with all the dialog values
        heroTextBean.setHeadingText(heading);
        heroTextBean.setDescription(description); 
        heroTextBean.setPath(path); 
        heroTextBean.setDate(date); 
        heroTextBean.setShow(show);
        heroTextBean.setType(type);
      }
       
  public HeroTextBean getHeroTextBean() {
        return this.heroTextBean;
    }
}

Modify the Project POM files

Add the following POM dependency to the POM file located at C:\AdobeCQ\Lab2018. Make sure that you place these the new dependencies under the <dependencies> element here:

<!-- ====================================================================== -->

    <!-- D E P E N D E N C I E S                                                -->

    <!-- ====================================================================== -->

    <dependencyManagement>

        <dependencies>

 

Add these two dependencies. 

<!-- OSGi Dependencies -->
  <dependency>
      <groupId>com.adobe.aem</groupId>
       <artifactId>uber-jar</artifactId>
       <version>6.3.0</version>
   <classifier>obfuscated-apis</classifier>
   <scope>provided</scope>
   </dependency>
   
   <dependency>
      <groupId>org.apache.geronimo.specs</groupId>
      <artifactId>geronimo-atinject_1.0_spec</artifactId>
      <version>1.0</version>
      <scope>provided</scope>
   </dependency>

Next add the following dependencies to the POM file displayed in the Eclipse IDE (under Lab2018\core). Once again, make sure that you add these below the <dependencies> element.

<dependency>
      <groupId>com.adobe.aem</groupId>
      <artifactId>uber-jar</artifactId>
       <classifier>obfuscated-apis</classifier>
  </dependency>
   
  <dependency>
        <groupId>org.apache.geronimo.specs</groupId>
        <artifactId>geronimo-atinject_1.0_spec</artifactId>
  </dependency>

Build the OSGi bundle using Maven

Build the OSGi bundle by using Maven. You are going to use a Maven command that only builds the bundle and does not deploy to the project Experience Manager. The reason is you do not want to overwrite your project under /apps/Lab2018.

To build the OSGi bundle by using Maven, perform these steps:

1. Open the command prompt and go to the C:\AdobeCQ\Lab2018.

2. Run the following maven command: mvn clean install.

3. The OSGi component can be found in the following folder: C:\AdobeCQ\ Lab2018\core\target. The file name of the OSGi component is Lab2018.core-1.0-SNAPSHOT.jar.
 

Note:

DO NOT RUN mvn PautoInstallPackage install as this will overwrite your changes in CRXDE lite.

Deploy the bundle to Experience Manager

Manually deploy the OSGi bundle to Experience Manager by performing these tasks:

1. Login to the Apache Felix Web Console at http://server:port/system/console/bundles (default admin user = admin with password= admin).

2. Click the Bundles tab, sort the bundle list by Id, and note the Id of the last bundle.

3. Click the Install/Update button.

4. Browse to the bundle JAR file you just built using Maven.

5. Click Install.

6. Click the Refresh Packages button.

7. Check the bundle with the highest Id.

8. Click Active.

9. Your new bundle should now be listed with the status Active.
 

Modify the Component HTML to interaction with the HeroTextComponent class

You need to modify the firstcomponent.html to retrieve values from the HeroTextComponent class. Instead of reading property values set by the dialog, you are going to read the values from the HeroTextComponent class. Replace the code in the firstcomponent.html file with this code.

<div>
<p>This is your AEM HTML Template Language component using WCMUsePojo</p>
<div data-sly-use.heroTextObject="com.aem.summit.core.HeroTextComponent" data-sly-test="${heroTextObject}">
		<p>The following values are the resource types added to the dialog</p>
       <h1>${heroTextObject.heroTextBean.headingText}</h1>
       <p><b>Description:</b> ${heroTextObject.heroTextBean.description}</p>
       <p><b>Selected Path value:</b> ${heroTextObject.heroTextBean.path}</p>  
       <p><b>Date:</b> ${heroTextObject.heroTextBean.date}</p> 
       <p><b>Size:</b> ${heroTextObject.heroTextBean.type}</p>  
       <p><b>CHeckbox:</b> ${heroTextObject.heroTextBean.show}</p>  
</div>

In this example, notice data-sly-use.heroTextObject references the Java component: com.aem.summit.core.HeroTextComponent.

The code:

data-sly-test="${heroTextObject}"

checks whether the heroTextObject is null. Next notice these lines of code:

<h1>${heroTextObject.heroTextBean.headingText}</h1>
<p>${heroTextObject.heroTextBean.description}</p>

This is how you interact with the Java server-side part of the component. In this example, you are writing out the value of the heroTextBean object's headingText class member in an HTML h1 tag. You defined the headingText data member when you created the Java code. This is the value that the user entered in the component's headingtext dialog field.
Next the value of the heroTextBean object's description class member in an HTML p tag. This is the value that the user entered in the component's description field.

NOTE: The rest of the data members are written out like the description data member.
 

Refresh the Web Page

When you refresh the web page, you will see the values written out from the Java WCMUsePojo class.

Client1
Values displayed from WCMUsePojo

Note:

The rest of the data members are written out like the description data member.

Use a DataSource Object to populate a Select field

In a previous section, you created a Select field that has three nodes that represents the values that are displayed in the dialog. In this section, you are going to learn how to use a com.adobe.granite.ui.components.ds.DataSource object to populate the Select field with a list of countries by using Java code.

By using Java code, you can dynamically populate the Select field. For example, you can invoke a 3rd party Restful service and populate the Select field with those values.The following illustration shows the Select field containing a list of countries. 

 

Client2
A list of countries displayed within the Select field

You can use a WCMUsePojo class to create the DataSource object and bind that to the Select field. This replaces the use of the child nodes under the Select node.

Download

Add the HtlDataSourceExample class to the Java project

The HtlDataSourceExample class extends WCMUsePojo and creates a DataSource object that is used to populate the Select field located in the component's dialog. In this example, notice a Map object named countries is created and populated with country names. These values are displayed in the Select field.

In your Java project, create a class named HtlDataSourceExample in the com.aem.summit.core package (refer to the previous section to instructions on how to create a class in Eclipse). Add the following Java code to this class.

 

package com.aem.summit.core;
import java.util.HashMap;
import java.util.Map; 
import java.util.LinkedHashMap;
import java.util.List;
  
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
  
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.iterators.TransformIterator; 
import org.apache.commons.collections.iterators.*;
  
import com.adobe.cq.sightly.WCMUsePojo;
import com.adobe.granite.ui.components.ds.DataSource;
import com.adobe.granite.ui.components.ds.SimpleDataSource;
import com.adobe.granite.ui.components.ds.ValueMapResource;
  
public class HtlDataSourceExample extends WCMUsePojo
{
  
@Override
 public void activate() throws Exception {
 final ResourceResolver resolver = getResource().getResourceResolver();
  
//Creating the Map instance to insert the countries
 final Map<String, String> countries = new LinkedHashMap<String, String>();
  
 countries.put("in", "India");
 countries.put("us", "United States");
 countries.put("aus", "Australia");
 countries.put("pak", "Pakistan");
 countries.put("sri", "Srilanka");
  
 @SuppressWarnings("unchecked")
  
//Creating the Datasource Object for populating the drop-down control.
 DataSource ds = new SimpleDataSource(new TransformIterator(countries.keySet().iterator(), new Transformer() {
  
 @Override
  
//Transforms the input object into output object
 public Object transform(Object o) {
 String country = (String) o;
  
//Allocating memory to Map
 ValueMap vm = new ValueMapDecorator(new HashMap<String, Object>());
  
//Populate the Map
 vm.put("value", country);
 vm.put("text", countries.get(country));
  
 return new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", vm);
 }
 }));
  
 this.getRequest().setAttribute(DataSource.class.getName(), ds);
  
 }
}

Update the POM dependencies

Update the dependencies section under core (Lab2018/core). Replace that dependencies section with the following dependencies.

<dependencies>
        <!-- OSGi Dependencies -->
        <dependency>
            <groupId>com.adobe.aem</groupId>
            <artifactId>uber-jar</artifactId>
            <classifier>obfuscated-apis</classifier>
        </dependency>
         
        <dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.1</version>
</dependency>
   
        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-atinject_1.0_spec</artifactId>
        </dependency>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>osgi.core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>osgi.cmpn</artifactId>
        </dependency>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>osgi.annotation</artifactId>
        </dependency>
        <!-- Other Dependencies -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.jcr</groupId>
            <artifactId>jcr</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
        </dependency>
        <dependency>
            <groupId>com.adobe.aem</groupId>
            <artifactId>uber-jar</artifactId>
            <classifier>apis</classifier>
        </dependency>
        <dependency>
            <groupId>org.apache.sling</groupId>
            <artifactId>org.apache.sling.models.api</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
        </dependency>
        <dependency>
            <groupId>junit-addons</groupId>
            <artifactId>junit-addons</artifactId>
        </dependency>
    </dependencies>
</project>

Once you update the dependencies, then rebuild the OSGi bundle and re-deploy it.

Note:

Refer to the instructions in the Section titled Build the OSGi bundle using Maven for information on how to build and deploy the OSGi bundle. Do NOT USE mvn PautoInstallPackage. Use mvn clean install.

Modify the Dialog JCR Nodes

You need to modify the nodes in the components JCR dialog. Create a node that binds to the DataSource object that you created so the Select field is populated with the DataSource instead of child nodes (created in a previous section).

The following illustration shows the JCR dialog node that you create in this section.
 

Nodes1
New dialog nodes

Perform these tasks in CRXDE Lite.

1. Change the fieldLabel property of /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items/type to Country.

2. Delete the items node located here: /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items/type/items.

3. Click on the /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items/type node.


3. Right click and select Create, Create Node. Enter the following values:

  • Name: datasource
  • Type: nt:unstructured

4. Add the following property to the datasource node.

  • sling:resourceType (String) - /apps/Lab2018/components/datasource/mylist/mylist.html (this value points to the JCR node where the HTL script is located. The HTL gets the DataSource object defined in the HtlDataSourceExample Java class. )
     

Add a HTL script to the component folder

Next create the HTL script that retrieves the DataSource object that is defined in the HtlDataSourceExample class. This object is used to populate the drop-down field located in the component dialog.

To create the DataSource script, perform these steps using CRXDE lite:

1. Click /apps/Lab2018/components.

2. Right click, and select Create, Create Folder.

3. Name the folder datasource.

4. Under the datasource folder, create another folder named mylist.

5. Under the mylist folder, create a file named mylist.html.

6. Add the HTL code displayed in this section to this HTML file.

<sly data-sly-use.data="com.aem.summit.core.HtlDataSourceExample">
</sly>

 

Refresh the Web Page

Before refreshing the web page, modify one line of code in the firstcomponent.html. Replace this line of code:

<p><b>Size:</b> ${heroTextObject.heroTextBean.type}</p>

With this line of code:

<p><b>Country:</b> ${heroTextObject.heroTextBean.type}</p>

When you refresh the web page, and open the dialog, you will see the new values in the Select field. Pick a country and click the check mark. Now you will see the selected country in the web page.
 

Client3
The Select field displays a different value based on the DataSource object

Note:

Make sure that your OSGi bundle is in an Active State, otherwise, the page does not load properly. 

Using the AutoComplete Feature

You can use a granite/ui/components/coral/foundation/form/autocomplete resource type to present the user of the component with a list of suggestions. Refer to the following video. 


To create a Touch UI component dialog with autocomplete functionality, perform these steps. 

1. Change the resource type of the type node to granite/ui/components/coral/foundation/form/autocomplete located here: 

/apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items/type

2. Create an options nodes parallel to datasource node and set the sling:resourceType property to granite/ui/components/coral/foundation/form/autocomplete/list.

The following illustration shows the AEM JCR branch. 

AutoComplete
Setting up an autocomplete feature in the Touch UI dialog

Use multiple DataSource Objects to populate multiple Select fields

You can populate two different Select fields in an AEM component dialog with two different com.adobe.granite.ui.components.ds.DataSource objects. This section illustrates how to use two different DataSource objects to populate two different Select fields, as shown in the following illustration. 

MultiSelect
A second Select field being populated by a second DataSource object

Download

Modify the Dialog JCR Nodes

You need to modify the nodes in the components JCR dialog. Create a second node that binds to the second DataSource object.

The following illustration shows the JCR dialog node that you create in this section.

SecondSelectNode
A new select node

Perform these tasks in CRXDE Lite.

1. Add a new node named type2 to /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items.

2. Add the following properties to this node: 

  • fieldDescription (String) - Select Fruit
  • fieldLabel (String) - Fruit
  • name (Strong) - ./fruit
  • sling:resourceType (String) - granite/ui/components/coral/foundation/form/select

3. Right click on the type2 node and select Create, Create Node. Enter the following values:

  • Name: datasource
  • Type: nt:unstructured

4. Add the following property to the datasource node.

  • sling:resourceType (String) - /apps/Lab2018/components/datasource/mylist/myFruit.html (this value obtains data from the second DataSource object defined in the HtlDataSourceFruit Java class. )
     

Modify Java Classes

Modify these Java classes:

1. Add a new Class named HtlDataSourceFruit.

2. Add Java logic to the HeroTextComponent class to read the new field. 

3. Modify the HeroTextBean class to add a new field. 

HtlDataSourceFruit

Add a new class named HtlDataSourceFruit to the package named com.aem.summit.core. Add the following Java code to this class. 

package com.aem.summit.core;


import java.util.HashMap;
import java.util.Map; 
import java.util.LinkedHashMap;
import java.util.List;
  
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
  
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.iterators.TransformIterator; 
import org.apache.commons.collections.iterators.*;
  
import com.adobe.cq.sightly.WCMUsePojo;
import com.adobe.granite.ui.components.ds.DataSource;
import com.adobe.granite.ui.components.ds.SimpleDataSource;
import com.adobe.granite.ui.components.ds.ValueMapResource;
  
public class HtlDataSourceFruit extends WCMUsePojo
{
  
@Override
 public void activate() throws Exception {
 final ResourceResolver resolver = getResource().getResourceResolver();
  
//Creating the Map instance to insert the countries
 final Map<String, String> fruits = new LinkedHashMap<String, String>();
  
 fruits.put("orange", "Orange");
 fruits.put("apple", "Apple");
 fruits.put("pear", "Pear");
 fruits.put("banana", "Banana");
 fruits.put("grapes", "Grapes");
  
 @SuppressWarnings("unchecked")
  
//Creating the Datasource Object for populating the drop-down control.
 DataSource ds = new SimpleDataSource(new TransformIterator(fruits.keySet().iterator(), new Transformer() {
  
 @Override
  
//Transforms the input object into output object
 public Object transform(Object o) {
 String fruit = (String) o;
  
//Allocating memory to Map
 ValueMap vm = new ValueMapDecorator(new HashMap<String, Object>());
  
//Populate the Map
 vm.put("value", fruit);
 vm.put("text", fruits.get(fruit));
  
 return new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", vm);
 }
 }));
  
 this.getRequest().setAttribute(DataSource.class.getName(), ds);
  
 }
}

HeroTextBean

Add the following code to the HeroTextBean class. This new code handles the data from the second Select field in the component dialog. 

/** Stores Select  information */
    private String fruit; 
    
    public String getFruit() {
        return this.fruit;
    }
    /**
     * @param path the path to set
     */
    public void setFruit(String fruit) {
        this.fruit = fruit;
    }

HeroTextComponent

Replace the HeroTextComponent class with this Java code. Notice new lines of code are added to handle the input from the fruit field (the second select in the component dialog). 

package com.aem.summit.core;
 
import com.adobe.cq.sightly.WCMUsePojo;
import com.aem.summit.core.HeroTextBean;
   
public class HeroTextComponent
extends WCMUsePojo
{
   
     /** The hero text bean. */
    private HeroTextBean heroTextBean = null;
        
    @Override
    public void activate() throws Exception {
            
         heroTextBean = new HeroTextBean();
                
        //Get the values that the author entered into the AEM dialog
        String heading = getProperties().get("heading", "");
        String description = getProperties().get("description","");
        String path = getProperties().get("path","");
        String date = getProperties().get("startdate","");
        String show = getProperties().get("show","");
        String type = getProperties().get("size","");
        String fruit = getProperties().get("fruit","");
      
         //Set the Bean with all the dialog values
        heroTextBean.setHeadingText(heading);
        heroTextBean.setDescription(description); 
        heroTextBean.setPath(path); 
        heroTextBean.setDate(date); 
        heroTextBean.setShow(show);
        heroTextBean.setType(type);
        heroTextBean.setFruit(fruit);
      }
        
  public HeroTextBean getHeroTextBean() {
        return this.heroTextBean;
    }
}

Add a HTL script to the component folder

Next create the HTL script that retrieves the DataSource object that is defined in the HtlDataSourceExample class. This object is used to populate the drop-down field located in the component dialog.

To create the second DataSource script, perform these steps using CRXDE lite:

1. Click /apps/Lab2018/components/datasource/mylist.

2. Under the mylist folder, create a file named myfruit.html.

3. Add this HTL code to this HTML file.

<sly data-sly-use.data="com.aem.summit.core.HtlDataSourceFruit">

</sly>

Modify the HTL Script

Modify the HTL script located here: /apps/Lab2018/components/content/firstcomponent/firstcomponent.html/

Replace the existing code with this code: 

 

<p>This is your AEM HTML Template Language component using WCMUsePojo</p>
<div data-sly-use.heroTextObject="com.aem.summit.core.HeroTextComponent" data-sly-test="${heroTextObject}">

		<p>The following values are the resource types added to the dialog</p>
       <h1>${heroTextObject.heroTextBean.headingText}</h1>
       <p><b>Description:</b> ${heroTextObject.heroTextBean.description}</p>
       <p><b>Selected Path value:</b> ${heroTextObject.heroTextBean.path}</p>  
       <p><b>Date:</b> ${heroTextObject.heroTextBean.date}</p> 
       <p><b>Country:</b> ${heroTextObject.heroTextBean.type}</p> 
       <p><b>Fruit:</b> ${heroTextObject.heroTextBean.fruit}</p> 
       <p><b>CHeckbox:</b> ${heroTextObject.heroTextBean.show}</p>  
</div>

After you make all of the changes in this section to your project, you notice that the component dialog is being populated with two different DataSource objects, as shown in this video. 

Using Multiple DataSource objects to populate Multiple Select fields

Using Multiple DataSource objects to populate Multiple Select fields
Using Multiple DataSource objects to populate Multiple Select fields

Use a Sling Servlet to populate a Select Field

In this section of the article, a Sling Servlet is used to populate the Select Field. Furthermore, a JSON data source is read from the JCR that cotains text and values. Assume that the following JSON is used to populate the Select field. 

[  
   {  
      "text":"foo",
      "value":1
   },
   {  
      "text":"bar",
      "value":2
   },
   {  
      "text":"baz",
      "value":3
   }
]

Next, assume that this JSON is stored as a node in this JCR location: 

/content/jsondata/jsondata.txt

as shown in this illustration. 

JSON
JSON data

Using a Sling Servlet, you can read this JSON data and populate a DataSource object, which is used to populate the Select field in the component dialog. In this example, the Sling Servlet is registered by using a Resource type.

Change the /apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/herotext/items/column/items/type/datasource node's sling:resourceType property to: 

/apps/aem63lab/dailog/dropdown/json

This value maps to this value in the Sling Servlet. 

@Component(service = Servlet.class, immediate = true, property = {
  Constants.SERVICE_DESCRIPTION + "=Component Dropdown option fetching through Servlet",
  "sling.servlet.resourceTypes=/apps/aem63lab/dailog/dropdown/json",
  "sling.servlet.methods=" + HttpConstants.METHOD_GET })
public class DatasourceJson extends SlingSafeMethodsServlet {

When the dialog is opened, the Sling Servlet is invoked, the JSON is read and used to populate the Select field, as shown in this illustration. 

 




JSONDialog
The values in the JSON data are now displayed in the Select field

The following Java represents the Sling Servlet that reads the JSON data and creates a DataSource object. 

package com.aem.summit.core.servlets;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.jcr.Node;
import javax.servlet.Servlet;
import javax.servlet.ServletException;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONObject;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.cq.commerce.common.ValueMapDecorator;
import com.adobe.granite.ui.components.ds.DataSource;
import com.adobe.granite.ui.components.ds.EmptyDataSource;
import com.adobe.granite.ui.components.ds.SimpleDataSource;
import com.adobe.granite.ui.components.ds.ValueMapResource;

@Component(service = Servlet.class, immediate = true, property = {
		Constants.SERVICE_DESCRIPTION + "=Component Dropdown option fetching through Servlet",
		"sling.servlet.resourceTypes=/apps/aem63lab/dailog/dropdown/json",
		"sling.servlet.methods=" + HttpConstants.METHOD_GET })
public class DatasourceJson extends SlingSafeMethodsServlet {

	private static final long serialVersionUID = 1L;
	Logger logger = LoggerFactory.getLogger(this.getClass());

	
	protected final String OPTIONS_PROPERTY = "options";

	@Override
	protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
			throws ServletException, IOException {
		try {
			ResourceResolver resolver = request.getResourceResolver();
			// set fallback
			request.setAttribute(DataSource.class.getName(), EmptyDataSource.instance());
		
			Resource datasource = request.getResource().getChild("datasource");
			ValueMap dsProperties = ResourceUtil.getValueMap(datasource);
			String genericListPath = "data";
			
			logger.info("In Servlet");
			
			if(genericListPath != null) {
				//Create a node that represents the root node
				 
				String resourcePath = "/content/jsondata/jsondata.txt/jcr:content";
				Node cfNode = request.getResource().getResourceResolver().getResource(resourcePath).adaptTo(Node.class);
				InputStream in = cfNode.getProperty("jcr:data").getBinary().getStream();
				BufferedReader reader = new BufferedReader(new InputStreamReader(in));
				StringBuilder out = new StringBuilder();
				String line;
				while ((line = reader.readLine()) != null) {
					out.append(line);
				}
				reader.close();
				
				JSONArray jsonArray = new JSONArray(out.toString()); 
				ValueMap vm = null;
				List<Resource> optionResourceList = new ArrayList<Resource>();

				for (int i = 0; i < jsonArray.length(); i++) {
				    JSONObject json = jsonArray.getJSONObject(i);
				    String Text = "";
					String Value = "";
					vm = new ValueMapDecorator(new HashMap<String, Object>());
					Text = json.getString("text");
					Value = json.getString("value");

					vm.put("value", Value);
					vm.put("text", Text);
					optionResourceList
					.add(new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", vm));

				}
						DataSource ds = new SimpleDataSource(optionResourceList.iterator());
					request.setAttribute(DataSource.class.getName(), ds);

				} else {
					logger.info("JSON file is not found ");
				}
		}
			
				catch(Exception e)
	{
		logger.info("Error in Get Drop Down Values", e);
	}
}

}

Use Sling Models with your component

In the previous sections, you learned how to create an HTL component that uses various sling resource types in its dialog. You also learned how to read the dialog values using HTL code and Java code that extends the WCMUsePojo class.

In this section, you are going to learn to use Sling Models instead of WCMUsePojo. Like WCMUsePojo, a Sling Model uses a Java class where you can read the dialog values. Instead of reading the dialog values by calling the getProperties method, you use the @inject annotation.
 

Download

Add a Sling Model Java class to your Lab2018 project

Add a Java classes to Eclipse by performing these tasks.

1. Open Eclipse to Lab2018.
2. In the Package Explorer, click on the com.aem.summit.core.models package.
3. Click and Select New, Class.
4. Name the class HeroSlingModel.

Once done, your project resembles the following illustration.
 

Client4
Add a Sling Model Class

Add Java code to the HeroSlingModel Class

The HeroSlingModel class uses Sling Models annotation. Notice that the class uses this annotation:

@Model(adaptables = Resource.class)

For each field in the dialog that you want to read, create a data member that matches the node name. Each data member uses the @Inject annotation. For example, consider the description field in the dialog.

@Inject @Optional
public String description

What is happening here is the value that the AEM author enters into the AEM component dialog field (for example, description) is injected into this data member.

Notice that this class has a method named init that uses this annotation.

@PostConstruct

This is the method that is invoked when an author clicks the checkmark in the component dialog. All that is happening in this method is a HeroTextBean object is created. The dialog values are injected into the data members and then added to the HeroTextBean object by invoking the corresponding method. For example, the path value is added by invoking the HeroTextBean objects setPath method.

Add the following Java code to the HeroSlingModel class.
 

package com.aem.summit.core.models;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import com.aem.summit.core.HeroTextBean; 
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Optional;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Model(adaptables = Resource.class)
public class HeroSlingModel {
	
	private final Logger LOG = LoggerFactory.getLogger(getClass());
	
	//Get all dialog fields by using the inject annotation
	@Inject @Optional
    public String heading;
 
    @Inject @Optional
    public String description;
    
    @Inject @Optional
    public String path;
    
    @Inject @Optional
    public String startdate;
    
    @Inject @Optional
    public String show;
    
    @Inject @Optional
    public String size;
    
    /** The hero text bean. */
    private HeroTextBean heroTextBean = null;
    
    @PostConstruct
    protected void init() {
        LOG.info("In the  **** INIT *** method");
        
        heroTextBean = new HeroTextBean();
        
        //Set the Bean with all the dialgo values
        heroTextBean.setHeadingText(heading);
        heroTextBean.setDescription(description); 
        heroTextBean.setPath(path); 
        heroTextBean.setDate(startdate); 
        
  //If checkbox is unchecked
  if (show == null)
        	heroTextBean.setShow("off");
        else
        	   heroTextBean.setShow(show);
        heroTextBean.setType(size);
     
    }
    public HeroTextBean getHeroTextBean() {
        return this.heroTextBean;
    }
}

Note:

In this example, we checked for a null value for the checkbox. This occurs when the checkbox is unchecked. If the values is null, we hard code a value for the checkbox.

Refer to the instructions in the previous Section for information on how to build and deploy the OSGi bundle. Do NOT USE mvn -PautoInstallPackage. Use mvn clean install.

 

Modify the Component HTML to interact with the HeroSlingModel class

You need to modify the firstcomponent.html to retrieve values from the HeroSlingModel class. You are going to read the values from the HeroSlingModel class. Add the following code to the firstcomponent.html.
 

<div>
<p>This is your AEM HTML Template Language component using a Sling Model:</p>
<div data-sly-use.heroTextObject="com.aem.summit.core.models.HeroSlingModel" data-sly-test="${heroTextObject}">

	   <h1>${heroTextObject.heroTextBean.headingText}</h1>
       <p><b>Description:</b> ${heroTextObject.heroTextBean.description}</p>
       <p><b>Selected Path value:</b> ${heroTextObject.heroTextBean.path}</p>  
       <p><b>Date:</b> ${heroTextObject.heroTextBean.date}</p> 
       <p><b>Country:</b> ${heroTextObject.heroTextBean.type}</p>  
       <p><b>CHeckbox:</b> ${heroTextObject.heroTextBean.show}</p>  

</div> 

In this example, notice data-sly-use.heroTextObject references the Java Sling Model class: com.aem.summit.core.models.HeroSlingModel.

The code:

data-sly-test="${heroTextObject}"

checks whether the heroTextObject is null.

Next notice these lines of code:

<h1>${heroTextObject.heroTextBean.headingText}</h1>
<p>${heroTextObject.heroTextBean.description}</p>

This is how you interact with the Java server-side part of the component. In this example, you are writing out the value of the heroTextBean object's headingText class member in an HTML h1 tag.

You defined the headingText data member when you created the Java code. This is the value that the user entered in the component's headingtext dialog field.

Next the value of the heroTextBean object's description class member in an HTML p tag. This is the value that the user entered in the component's description field.

The rest of the data members are written out like the description data member.
 

Refresh the Web Page

Open the dialog and enter new values. When you refresh the web page, you will see the values written out from the Java Sling Model class.

Client5
Values displayed from the Sling Model class

Use a Multifield in your component

The final section walks you through how to work with Sling Models and a MultiField resource type, which is granite/ui/components/coral/foundation/form/multifield. That is, you can use a Granite/Coral MultiField data type to build a dialog that lets an author enter information into a MultiField control in the component's dialog, as shown in this illustration.

MF-Radio6
A multifield displayed in a component dialog

Download

The following illustration shows you the dialog nodes that create the multifield.

MF-Radio
JCR Nodes that create the dialog

Note:

When you install the package, the name of the path node is ./pathbr.

Notice the first arrow that points to the products node. This is the multifield node. Each multifield contains the following Granite/Coral resource type:

The MultiField in this article has the following fields based on Granite/Coral data types:

  • A text field based on granite/ui/components/coral/foundation/form/textfield.
  • A path browser based on granite/ui/components/coral/foundation/form/pathbrowser.
  • A date picker based on granite/ui/components/coral/foundation/form/datepicker.
  • A checkbox based on granite/ui/components/coral/foundation/form/checkbox. 
  • A select (drop-down) based on granite/ui/components/coral/foundation/form/select.
  • A group of radio buttons based on granite/ui/components/coral/foundation/form/radio

Look at the JCR dialog node that is under the firstcomponent.
 

Modify the HeroSlingModel Class

Modify the HeroSlingModel class to handle the MultiField. The HeroSlingModel class uses an @inject annotation that injects a resource type (based on the node in the dialog) that corresponds to the granite/ui/components/coral/foundation/form/multifield (you are injecting the multifield into the Sling Model). 

You can see this node at this JCR location:

/apps/Lab2018/components/content/firstcomponent/cq:dialog/content/items/column/items/products

Replace the Java code in the HeroSlingModel class with the following Java code.
 

package com.aem.summit.core.models;
import javax.annotation.PostConstruct;
import javax.inject.Inject;

import com.aem.summit.core.HeroTextBean; 
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Model(adaptables = Resource.class)
public class HeroSlingModel {
	
	private final Logger LOG = LoggerFactory.getLogger(getClass());
	 // Inject the products node under the current node
    @Inject
    @Optional
    public Resource products;
 
    // No need of a post construct as we don't have anything to modify after the
    // model is constructed
}

Note:

The name of the Resource object must match the name of the Multifield node, which in this example is products.

 

Refer to the instructions in the Previous Section  for information on how to build and deploy the OSGi bundle. Do NOT USE mvn -PautoInstallPackage. Use mvn clean install.

Modify the Component HTML

You need to modify the firstcomponent.html to retrieve values from the HeroSlingModel class in which a MultiField resource is injected. You are going to read the values from the HeroSlingModel class.
Add the following code to the firstcomponent.html.
 

<h2>This is your AEM HTML Template Language component with a Multifield</h2>
<div
    data-sly-use.multiItems="com.aem.summit.core.models.HeroSlingModel">
    <div data-sly-list.head="${multiItems.products.listChildren}">
 
 
        <p><b>Description:</b> ${head.product}</p>
       <p><b>Selected Path value:</b> ${head.pathbr}</p>
        <p><b>Date:</b> ${'yyyy-MM-dd HH:mm:ss.SSSXXX' @ format= head.startDate, timezone='UTC'}</p> 
       <p><b>Country:</b> ${head.size}</p>  
       <p><b>CHeckbox:</b> ${head.show}</p>
	   <p><b>Fruit:</b> ${head.fruit}</p>	
      <hr>
   </div>
</div>

In this example, notice data-sly-use.multiItems references the Java Sling Model class: com.aem.summit.core.models.HeroSlingModel.

The code:

div data-sly-list.head="${multiItems.products.listChildren}">

handles the MultiField.

For each MultiField in the dialog, the following code is executed.

<p><b>Description:</b> ${head.product}</p>
<p><b>Selected Path value:</b> ${head.pathbr}</p>
<p><b>Date:</b> ${'yyyy-MM-dd HH:mm:ss.SSSXXX' @ format= head.startDate, timezone='UTC'}</p>
<p><b>Country:</b> ${head.size}</p>
<p><b>CHeckbox:</b> ${head.show}</p>

 

Refresh the Web Page

Open the dialog and fill in Multifield values.

MF-Radio1
A Component dialog that contains a Multifield

When you enter new values into the dialog and refresh the web page, you will see the values written out from the Java Sling Model class.

MF-Radio5
Multifield data is rendered in an AEM component

Understanding where Granite/Coral Multifield dialog data is stored

By default, Granite/Coral MultiField data is stored as child nodes:

/content/Lab2018/en/jcr:content/par/firstcomponent/products

This is shown in the following illustration. Notice that each MultiField is a separate node. In this example, item0 and item1. Dialog field values are stored as properties, as shown here.
 

MF3
The location where Multifield data is stored

See also

Join the AEM community at: Adobe Experience Manager Community

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License  Twitter™ and Facebook posts are not covered under the terms of Creative Commons.

Legal Notices   |   Online Privacy Policy