Using three valued logic in Touch UI dialog checkboxes

20 June 2016
Piotr Wilczynski
Frink_Cognifide_2016_HeaderImages_0117

Welcome to the fourth instalment in our blog series on Touch UI which explores how you can use Sling @Suffixes in Zen Garden to give you more control over content update.  As an AEM developer I want to be able to modify the process of updating content. For example, I may want to delete a property, use a default value or set type. There is a way to accomplish this goal using Sling. I will describe it using HTML checkbox as an example.

A checkbox in Touch UI only distinguishes two valued states:

  • null for initial state
  • true for checked

This logic is not sufficient for Zen Garden components. If we want to determine if a component is in initial state, we need to use three valued state logic:

  • null for initial state
  • false for unchecked
  • true for checked
To accomplish this goal Zen Garden uses SlingPostServlet @Suffixes. These suffixes provide you with more control over content update.  Here are three examples that are used in our checkbox scenario:
  • DefaultValue - set a property to a default value if there is no value provided in parameter (set the checkbox value to default if value is not provided).
  • Delete - removes a property while processing the content update request (when submitting an unchecked checkbox only this suffix is used which is why a third suffix is needed).
  • UseDefaultWhenMissing - set a property to a default value if there is no parameter submitted (set the checkbox value to default if a parameter is not submitted). 
<form method="POST" action="/content/page/first" enctype="multipart/form-data">
    <input name="queryIgnoreNoise" class="input" type="checkbox" value="true"/>
    <input type="hidden" name="queryIgnoreNoise@DefaultValue" value="false"/>
    <input type="hidden" name="queryIgnoreNoise@UseDefaultWhenMissing" value="true"/>
</form>

Based on this example, we can create a custom checkbox in a Touch UI dialog that aggregates three inputs.

  • The first is an ordinary granite checkbox with the value true (when checkbox is checked)
These next inputs are only hints for Sling on how to process our checkbox field, so we use them as hidden.
  • DefaultValue suffix is set to false, which will be used by a parameter with UseDefaultWhenMissing suffix.
  • UseDefaultWhenMissing suffix has no value, because it only indicates to use a value from parameter with DefaultValue suffix if no parameter is submitted.
These fields can be aggregated and treated as one new component:
<autoRotate
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/foundation/form/checkbox"
    fieldDescription="Check if carousel should auto rotate."
    name="./rotate"
    text="Auto rotate"
    value="{Boolean}true" />
<autoRotate-value-default
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/foundation/form/hidden"
    name="./rotate@DefaultValue"
    value="{Boolean}false" />
<autoRotate-value-when-missing
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/foundation/form/hidden"
    name="./rotate@UseDefaultWhenMissing" />

If we send such a form with a checked checkbox request, it will contain:

  • ./rotate parameter with value true which comes from the definition of field.

If we send it with an unchecked checkbox request, it will contain parameters:

  • ./rotate@Delete to delete a property
  • ./rotate@UseDefaultWhenMissing to apply a value from a parameter with a DefaultValue suffix.
  • ./rotate@DefaultValue to set a property to false

Sling @Suffixes are a bit complicated, but they do give you more control over content updates. There are even more useful ways to manipulate content available in the Sling documentation and you can read more about the migration of a component to Touch UI in  Building a Touch UI dialog with Zen Garden.