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

Article summary

Summary

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

 

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

Introduction

When creating components for Adobe Experience Manager (AEM) 6.5, 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

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 create an Experience Manager project named Lab2019. 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 16 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=16   -DarchetypeCatalog=https://repo.adobe.com/nexus/content/groups/public/

5. When prompted, specify the following information:

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

6. When prompted, specify Y.

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

tt
Build was successful

8. Open the Lab2019 folder and explore the generated project modules.
 

files

Import the AEM Project in Eclipse

You can import the project into Eclipse, as shown here. 

project
Eclipse Import Project Dialog

Note:

If you have not installed the Eclipse AEM Plug-in, then see the Weekend tutorial for information on how to perform this task: Getting Started with AEM Sites Chapter 1 - Project Setup at https://helpx.adobe.com/experience-manager/kt/sites/using/getting-started-wknd-tutorial-develop/part1.html.

Perform these tasks:

1. Open Eclipse that has the Eclipse Plug-in installed.

2. Click File > Import > Maven > Existing Maven Project.

3.  In the root directory, browse to Lab2019.

4. Go to Windows > Perspective > Open Perspective > AEM.

Setup the connection to the AEM Server

You can deploy project code changes directly from Eclipse to AEM. To perform this task, you need a connection to the server. This connection also helps in syncing changes made in CRXDE to the Eclipse project.

server
Default files

Perform these tasks:

1.  In the server panel, click to add new server.

2. Select Adobe Experience Manager server from the options.

3. Click Next.

4.  Select all modules in the available section and click the Add button.

5.  Click Finish.

6.  Double click Server to open the configuration window.

server

7. In the Connection section, change the port to 4502.

8. In the Publishing section, change the radio button to Never Publish Automatically.

9. Save (or Command+S) to save the configuration.

10.  Start the AEM Server.

You can use the AEM Server connection to pull code changes made in CRXDE.

Deploy the project using a Maven Build

You can use Eclipse and Maven to deploy the AEM project. The benefit of this process is it provides details of the build process in the console.

1. Right click on the 2019 parent module. 

text
The project imported into AEM

2. Click  Run As > Run Configurations.

MaVEN

3. Select Maven Build and add a new launch configuration.

4. Click Workspace and select the Lab2019 module.

5. In Goals, enter the following command: clean install.

6. In Profile, enter the following command: autoInstallPackage adobe-public.

7. Provide a name for this configuration - Deploy 2019 Package.

8. Click Apply > Run.

9. Next click Run.

This deploys your project to an AEM Server and you should receive a success message.

 

text
Edit the Lab2018 page


11.  Go to CRXDE Lite at http://localhost:4502/crx/de.

12. You can verify successful deployment by checking the following path: /apps/Lab2019.

crx
Delete the default components

View the Default page

You can view the default page for this project.

page
The default page without components

Perform these tasks:

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

2. Click the Navigation Icon.

3. Click Sites, Lab2019, English.

4. Click the Edit icon in the toolbar.

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.

text
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/Lab2019/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 Lab2019

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/Lab2019/components/content/firstcomponent

nodes
JCR nodes that make up the dialog

To build the dialog, perform these tasks:

1. Select /apps/Lab2019/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/Lab2019/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/Lab2019/components/content/firstcomponent/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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 Lab2019, 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.

client
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 Lab2019.
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.
 

crx
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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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/Lab2019/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.

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

text
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.

crx
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/Lab2019/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.
 

text
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.adobe.training.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 Lab2019 project

Add two Java classes to Eclipse by performing these tasks.

1. Open Eclipse to Lab2019.

2. In the Package Explorer, click on the com.adobe.training.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.
 

files
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.adobe.training.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.adobe.training.summit.core;

import com.adobe.cq.sightly.WCMUsePojo;
import com.adobe.training.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;
    }
}

Build the OSGi bundle using Maven

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

1. Right click on the summit parent module > Run As > Run Configurations.

2.  Select Maven Build and add a new launch configuration.

3. Click Workspace and select the summit parent module.

4. In Goals, enter the following command: clean install

5. In Profile, enter the following command: autoInstallBundle adobe-public

6. Provide a name for this configuration - Deploy Summit Package.

7.  Click Apply > Run.

Note:

autoInstallBundle only installs the OSGi bundle, not the entire package. 

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.adobe.training.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.adobe.training.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.

text
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.adobe.training.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.adobe.training.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

Add the following dependency to the CORE POM file in Eclipse. This is required to deploy the OSGi bundle to AEM. 

<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.1</version>
</dependency>

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

Note:

See the section in Section 4 to deploy the changes to AEM within an OSGi bundle

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.
 

dialog
New dialog nodes

Perform these tasks in CRXDE Lite.

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

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

3. Click on the /apps/Lab2019/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/Lab2019/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/Lab2019/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.
 

files
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/Lab2019/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

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/Lab2019/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/Lab2019/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.adobe.training.summit.core. Add the following Java code to this class. 

package com.adobe.training.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.adobe.training.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/Lab2019/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.adobe.training.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/Lab2019/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.adobe.training.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 Lab2019 project

Add a Java classes to Eclipse by performing these tasks.

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

Once done, your project resembles the following illustration.
 

server
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.adobe.training.summit.core.models;
 
import javax.annotation.PostConstruct;
import javax.inject.Inject;
 
import com.adobe.training.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 Sling Models</p>

<div data-sly-use.heroTextObject="com.adobe.training.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>

</div>

In this example, notice data-sly-use.heroTextObject references the Java Sling Model class: com.adobe.training.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.

project
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/Lab2019/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.adobe.training.summit.core.models;
 
import javax.annotation.PostConstruct;
import javax.inject.Inject;
 
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.adobe.training.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.adobe.training.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/Lab2019/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