DRY way of using RichText Granite UI Component in AEM for Static Templates

Every developer have experienced a situation where they are working with AEM multiple AEM components, where Touch UI dialogues consist of a common richtext Granite UI component configuration cq/gui/components/authoring/dialog/richtext. When I mention common richtext Granite UI component, I mean there are multiple AEM components that will have the richtext Granite UI component as one of it’s input fields, where only the “links*” and “format*” richtext features are enabled, as an example.

Enabling only the “links*” and “format*” richtext features, we catch ourselves repeating lines of code by copying and pasting the entire block of code for all of our Touch UI dialogues that require the richtext requirement. This works, but this is Write Everything Twice, “WET” code, and it’s not good implementation; this can be improved. What happens if there is a new requirement where the authors would like a new capability to the richtext field? Will we have to edit multiple dialogues? (like editing 20 component’s dialogues) The short answer is Yes. With this “WET” implementation, you must edit every single component’s dialogue configuration.

How can we do this better? How keep our code Don’t Repeat Yourself (DRY)?

Utilising the Granite UI component, granite/ui/components/coral/foundation/include, we are able to refer to common Granite UI component configurations in the JCR (that we are going to set up). Now changing the richtext configuration in one place will provide TouchUI dialogue changes to all 20+ components; see diagram below.

Advantages of using common richtext configurations

  • Ease to read and maintain
  • Reusability of the code
  • Reduces uneseccary lines of code in the repo
  • common Granite UI configs are easily accessible to manipulate

Multiple AEM components' Touch UI dialogue utilises the common Granite UI component configuration in the JCR, for the richtext Granite UI component configurations.

With the improvement, with the diagram above, you will notice multiple AEM components’ Touch UI dialogue utilises the common Granite UI component configuration in the JCR, for the richtext Granite UI component configurations.


The Implementation

In this section, code will be shared on how this configuration can be applied to your own AEM implementation. The example produced will be a summary of the diagram from above.

We will be creating a common richtext Granite UI configuration which will be referenced by a example component.

1. Register the common dialog namespace

We typically place the common Granite UI component configurations for “content TouchUI” in the JCR under a namespaced project, for example: /apps/sourcedcodeaem/components/dialogs/content/common.

/apps/sourcedcodeaem/components/dialogs/content/common

In the screenshot below, you will notice that there are already 3 folders that I have created.

  1. fields – fields that are commonly used by Touch UI dialogue configs (for this article we will only be focusing on these configs)
  2. fieldsets – fieldsets that are commonly used by Touch UI dialogue configs; these consist of more than 1 Granite UI component which is wrapped around a granite/ui/components/foundation/container.
  3. tabs – tabs that are commonly used by Touch UI dialogue configs; these consist of more than 1 Granite UI component which is wrapped around a granite/ui/components/foundation/container.

2. Create and configure the common Granite UI component configurations, under the “fields” structure

/apps/sourcedcodeaem/dialogs/content/common/fields/_cq_dialog/.content.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
    jcr:primaryType="nt:unstructured"
    jcr:title="Common Field Granite UI Config for Content Components"
    sling:resourceType="cq/gui/components/authoring/dialog">
    <commonFields
        jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/foundation/container">
        <items jcr:primaryType="nt:unstructured">
            <basicRTE
                jcr:primaryType="nt:unstructured"
                sling:resourceType="cq/gui/components/authoring/dialog/richtext">
                <rtePlugins jcr:primaryType="nt:unstructured">
                    <format
                        jcr:primaryType="nt:unstructured"
                        features="*"/>
                    <links
                        jcr:primaryType="nt:unstructured"
                        features="*"/>
                </rtePlugins>
                <uiSettings jcr:primaryType="nt:unstructured">
                    <cui jcr:primaryType="nt:unstructured">
                        <inline
                            jcr:primaryType="nt:unstructured"
                            toolbar="[links#modifylink,links#unlink,format#bold,format#italic]"/>
                        <dialogFullScreen
                            jcr:primaryType="nt:unstructured"
                            toolbar="[links#modifylink,links#unlink,format#bold,format#italic]"/>
                    </cui>
                </uiSettings>
            </basicRTE>
        </items>
    </commonFields>
</jcr:root>

3. From the targeted component, include the common Granite UI config

/apps/sourcedcodeaem/components/content/announcement

  • line:32 – the standard, cq/gui/components/authoring/dialog/richtext, Granite UI component is being referred.
  • line:38 – inclusion of the common richtext “rtePlugins” configuration, /apps/sourcedcodeaem/dialogs/content/common/fields/cq:dialog/commonFields/items/basicRTE/rtePlugins
  • line:42 – inclusion of the common richtext “uiSettings” configuration, /apps/sourcedcodeaem/dialogs/content/common/fields/cq:dialog/commonFields/items/basicRTE/uiSettings

Together with line:32,38,42 the common richtext component will be setup and ready to be used.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
    jcr:primaryType="nt:unstructured"
    jcr:title="Announcement Component"
    sling:resourceType="cq/gui/components/authoring/dialog">
    <content
        jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/foundation/container">
        <layout
            jcr:primaryType="nt:unstructured"
            sling:resourceType="granite/ui/components/foundation/layouts/tabs"
            type="nav"/>
        <items jcr:primaryType="nt:unstructured">
            <text
                jcr:primaryType="nt:unstructured"
                jcr:title="Hero Settings"
                sling:resourceType="granite/ui/components/foundation/section">
                <layout
                    jcr:primaryType="nt:unstructured"
                    sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"
                    margin="{Boolean}false"/>
                <items jcr:primaryType="nt:unstructured">
                    <column
                        jcr:primaryType="nt:unstructured"
                        sling:resourceType="granite/ui/components/foundation/container">
                        <items jcr:primaryType="nt:unstructured">
                            <headerText
                                    jcr:primaryType="nt:unstructured"
                                    sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                    fieldLabel="Title Text"
                                    name="./headerText"/>
                            <headingDescriptionText
                                    jcr:primaryType="nt:unstructured"
                                    sling:resourceType="cq/gui/components/authoring/dialog/richtext"
                                    name="./headingDescriptionText"
                                    required="true"
                                    useFixedInlineToolbar="{Boolean}true">
                                <rtePlugins
                                        jcr:primaryType="nt:unstructured"
                                        sling:resourceType="granite/ui/components/coral/foundation/include"
                                        path="/apps/sourcedcodeaem/dialogs/content/common/fields/cq:dialog/commonFields/items/basicRTE/rtePlugins"/>
                                <uiSettings
                                        jcr:primaryType="nt:unstructured"
                                        sling:resourceType="granite/ui/components/coral/foundation/include"
                                        path="/apps/sourcedcodeaem/dialogs/content/common/fields/cq:dialog/commonFields/items/basicRTE/uiSettings"/>
                            </headingDescriptionText>
                        </items>
                    </column>
                </items>
            </text>
        </items>
    </content>
</jcr:root>

4. Done

Now we have successfully referenced an AEM component to the common Touch UI dialogue field.
Announcement Component's Touch UI dialogue with a user interface of the common richtext configuration

Was this post helpful?

Hello, I am an Adobe AEM MVP & a certified Lead AEM Developer who is currently working as a Senior AEM Full Stack Developer at Whitbread, UK, London. I have 10 years of overall web engineering experience and 6 years of AEM experience in practice. I hope to give back to the AEM Full Stack Development community by sharing my knowledge with the world.

Leave a Reply

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

Back To Top