AEM Checkboxes and Semantic Property Types using the Sling Post Servlet

Adobe Experience Manager | AEM/CQ | Apache Sling

AEM Checkboxes and Semantic Property Types using the Sling Post Servlet

Using checkboxes in your Adobe Experience Manager component dialogs can be confusing to the new component developer. A few quick examples will reveal just how easy they really are. However, this article is meant to be more than a back-to-basics. We'll discuss best practices and take the opportunity to introduce the Sling Post Servlet. This is where many web developers and engineers have a breakthrough and recognize AEM for what it is - a powerful set of features and APIs, but at its core, it's simply an Apache Sling application.

Before diving into AEM's use of checkboxes, it's important to know the basics of how checkboxes are handled in ordinary HTML. Reading into the HTML5 specification , we find two important rules regarding checkboxes:

  1. "If the field element has a value attribute specified, then let value be the value of that attribute; otherwise, let value be the string 'on'." (See: 4.10.5.4 Common input element APIs, default/on)
  2. "When a form is submitted, only 'on' checkbox controls can become successful." (See: 4.10.22.4 Constructing the form data set)
The first bullet point simply means that the default value of a checkbox is the string literal "on" if a value attribute is not defined on the element. The second bullet point has much greater ramifications and will lead us into the topic of the Sling Post Servlet. The HTML specification states that while a checkbox in the on state is submitted with the default/on value, a checkbox in the off state is not submitted at all. The result is that the server will not receive a "false", null or "off" value for an unchecked checkbox, but rather will not receive either the name or a value in the form post.

The real power to control checkboxes in AEM is provided from the Sling Post Servlet. Sling provides nine suffixes, four of which we will concentrate on in this article. A suffix is used by submitting an additional request parameter with the parameter name appended with an "@" symbol and the suffix. For example, if you want to act on the "foo" parameter, you would submit "foo@SuffixName" in addition to the "foo" parameter.

Saving checkbox values as Boolean value types in the JCR

When posted to Sling and saved to the JCR, the default property type is String. While this is workable, wouldn't you rather have a Boolean value saved as a Boolean property type? When working in the strongly typed Java language you would use the boolean primitive or Boolean wrapper rather than a String literal to represent a Boolean value, so why not do the same in the JCR? You can use the Sling Post Servlet's TypeHint suffix to instruct Sling to set the property type as a Boolean (or other valid value type for that matter).

Removing checkbox values in the off state

In accordance with the HTML specification and as we previously discussed, an unchecked checkbox is not submitted. AEM takes care of this task for us when using the out-of-the-box Classic and Touch UI checkbox or selection controls. However, if you create something custom such as dynamically added checkboxes or checkboxgroups in your dialog, you might find that Sling and thus AEM is never notified when the author unchecks a checkbox. If you were unfamiliar with the Sling Post Servlet, you might end up writing a lot of JavaScript logic using listeners and the CQ Widget API's events. The better alternative is to use the Sling Post Servlet's Delete suffix. The Delete suffix instructs Sling to always delete the JCR property before taking action with the request parameters. If the checkbox is unchecked, the JCR property is deleted and since a value wasn't submitted, no property is created in its place. If the checkbox is checked, the JCR property is deleted and simply recreated with the new value, whether the value is the same as before or otherwise.

Setting checkbox values in the off state

The DefaultValue suffix instructs Sling to use a given default value should the request parameter not have a value. This alone isn't helpful in the case of an unchecked checkbox because neither the name nor value will be submitted. However, the DefaultValue will be considered when used in addition to the UseDefaultWhenMissing suffix because just as the suffix states, the value of an unchecked checkbox will be "missing" so the default value is used.

Tying it all together

So while you can use the Delete suffix to completely remove a JCR property, you can use the DefaultValue and UseDefaultWhenMissing in conjunction to guarantee that a JCR property will always be present with a value. In fact, by combining the TypeHint, DefaultValue and UseDefaultWhenMissing suffixes, you can ensure a semantically correct Boolean JCR property type is always created with a proper value of true or false.

cURL simulations

Run the following cURL commands against a running AEM/CQ instance and observe the JCR property values as well as the JCR property type.



AEM/CQ component dialogs

The most common checkbox control in the Classic UI is the CQ.form.Selection xtype with its type set to checkbox. By default the Selection/Checkbox control will save the JCR property as the String literal "true." You can use the TypeHint suffix to save the String value as a true Boolean by either setting the checkboxBoolTypeHint config option or by creating a CQ.Ext.form.Hidden field for the TypeHint request parameter.



You can also use Ext JS's CQ.Ext.form.Checkbox and CQ.Ext.form.CheckboxGroup xtypes in the Classic UI as the most basic checkbox controls. By default the Checkbox xtype will simply submit the default/on value, meaning if you don't specify a value, the default value is "on." You can use the inputValue config option to change the value to the String literal "true" and you can use the TypeHint suffix to save the String value as a proper Boolean.



In the new Granite Touch UI, use the granite/ui/components/foundation/form/checkbox resource to create the checkbox and the granite/ui/components/foundation/form/hidden resource for the TypeHint suffix. The checkbox resource has the deleteHint option to create the Sing Post Servlet Delete suffix for you.



Retrieving Boolean values

One point to keep in mind is that when you set a checkbox to checked as default dialog, the JCR property is not set until the dialog is opened and saved for the first time. A newly created component will not have that true Boolean value that your Sightly or JSP will be looking for. Therefore, you need to also make sure that your logic is defaults to the true value if the JCR property doesn't exist.



Conclusion

We discussed the basics and best practices of using checkboxes in AEM component dialogs. However, the checkboxes were a mere prelude into an introduction to the Sling Post Servlet. Hopefully you've come to realize what happens when you update a component; while AEM provides valuable functionality such as validation through Ext JS or Granite, ultimately, the component dialog is simply an HTML form posting to Apache Sling, which in turn handles the JCR update. We introduced four Sling Post Servlet Suffixes. It's important to know that their uses are not limited to checkboxes and that there are five other suffixes to explore, which are detailed in the documentation. You'll find that the Sling Post Servlet is extremely powerful and invaluable in the case of AEM component dialogs especially for checkboxes and multi-value properties.