May 4, 2020
Estimated Post Reading Time ~

Simple Touch UI Dialog Extensions for AEM

While there are a number of tools at a developer’s disposal to create clean, engaging dialogs within AEM, there are times when you may need to extend dialog functionalities in your Adobe Experience Manager implementation to suit your clients’ needs. Oftentimes, this can be achieved without too much effort.

As an exercise, we’ll use AEM 6.0 to create a Touch UI dialog. This dialog will contain a checkbox that toggles the visibility of a container that holds additional authorable fields.

Setting up the Dialog
There are two nodes that will be required to make our toggleable container in our Touch UI dialog: the toggle and the toggleable container itself. Each has its own important attributes. Let’s take a look at the cq:dialog.

We’ll start with the checkbox toggle:

<toggle
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/foundation/form/checkbox"
    text="Show/Hide Toggle"
    id="toggle"
    value="true"
    name="./toggle"
    class="showhide"
    showhide-target=".showhide-target"/>

There are a few key attributes that we want to look at here:
  • The “class” attribute will add that class to the checkbox when the dialog is rendered. This will allow us to target that checkbox later using JavaScript, allowing us to listen for any events on the checkbox. We’re using “showhide” as our class name.
  • The “value” attribute determines what the value of the checkbox will be when the checkbox is toggled.
  • The “showhide-target” will create a “data-showhide-target” attribute in our checkbox’s markup when the dialog is rendered. Our JavaScript will use this value to determine what it is we are trying to show or hide. We’ll target elements with the class name of “.showhide-target” for this example.
Let’s take a look at our toggleable container:

<someContainer
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/foundation/container"
    class="showhide-target"
    showhide-target-value="true">
    <items jcr:primaryType="nt:unstructured">
        <someInput
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/foundation/form/textfield"
                fieldDescription="You can only see me if you toggle the checkbox."
                fieldLabel="Some Input"
                name="./someInput"/>
        <someOtherInput
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/foundation/form/textfield"
                fieldDescription="You can only see me if you toggle the checkbox."
                fieldLabel="Some Other Input"
                name="./someOtherInput"/>
    </items>
</someContainer>

Above, we have a container with two textfields inside. We want to be able to show or hide this container dependent on whether or not our checkbox is checked. This container has two important attributes pertaining to our experiment:
  • The container’s “class” attribute will add the “showhide-target” class. Notice that this is the same class name that we are using in the “showhide-target” attribute of the checkbox. The toggle will target this container because of this class.
  • The “showhide-target-value” will create a “data-showhide-target” in our container’s markup when the dialog is rendered. This attribute will be set to the same value as the “value” attribute used in the checkbox. Our logic will check to see that our target container’s value of “true” matches that of the checkbox. If the checkbox is checked, they will match and we’ll show the container. If not, we’ll hide it.
Extending the Component with JavaScript
Our JavaScript will need to be added to a “cq:ClientLibraryFolder” that belongs to the “cq.authoring.dialog” category and depends on the “granite.jquery” client library. Let’s break down some of its functionality.

First, we’ll look at our event listeners.

$(document).on("foundation-contentloaded", function (e) {
  $(".showhide").each(function () {
    showHide($(this));
  });
});
 
$(document).on("change", ".showhide", function (e) {
  showHide($(this));
});

We’ve set up two listeners here. Our first will listen for the creation of our dialog (the “foundation-contentloaded” event). It will check for any toggle we may have set up and call the showHide function, passing the toggle object as a parameter. (Note: This allows us to see if a toggle is already checked when it is rendered. If it is, we’ll go ahead and show our toggleable container from the get-go.)

The second listener will look for any changes to the toggle. If a change event is triggered, we’ll again call the showHide function, passing the toggle object as a parameter.

Notice that we are looking for the “showhide” class in both listeners, which is the same class we gave to the checkbox toggle.

The showHide function is what is going to do the majority of the work:

function showHide(el) {
  var target = el.data("showhideTarget"),
    value = el.prop("checked") ? el.val() : "";
 
  // hide all targets by default
  $(target).not(".hide").addClass("hide");
 
  // show any targets with a matching target value
  $(target).filter("[data-showhide-target-value=\"" + value + "\"]").removeClass("hide");
}

This function will take the value of the checkbox (el) and compare it to the “data-showhide-target-value” of the toggleable container (target). If the values match, we’ll remove any “hide” class associated with the toggleable container. Otherwise, we’ll add that “hide” class to the container, which will hide it.

Here is a look at the JavaScript in its entirety:

(function (document, $) {
  "use strict";
 
  // listen for dialog injection
  $(document).on("foundation-contentloaded", function (e) {
    $(".showhide").each(function () {
      showHide($(this));
    });
  });
 
  // listen for toggle change
  $(document).on("change", ".showhide", function (e) {
    showHide($(this));
  });
 
  // show/hide our target depending on toggle state
  function showHide(el) {
    var target = el.data("showhideTarget"),
      value = el.prop("checked") ? el.val() : "";
 
    // hide all targets by default
    $(target).not(".hide").addClass("hide");
 
    // show any targets with a matching target value
    $(target).filter("[data-showhide-target-value=\"" + value + "\"]").removeClass("hide");
  }
 
})(document, Granite.$);

Through this simple exercise, you can see how easy it can be to build out more complex dialogs, allowing for a much-improved authoring experience for your clients.



By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.