AEM Dialog Components #3: Checkbox - Selezione Boolean

AEM Dialog Components #3: Checkbox

Cos'è un Checkbox?

Il Checkbox è un componente Granite UI che permette agli autori di abilitare o disabilitare un'opzione (valore boolean: true/false).

Casi d'uso comuni:

  • Mostra/nascondi elementi
  • Abilita/disabilita feature
  • Apri link in nuova tab
  • Opt-in newsletter
  • Flags di configurazione

Configurazione Base

XML Dialog Minimo

<showTitle
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    name="./showTitle"
    text="Show Title"
    value="{Boolean}true"/>

Proprietà essenziali:

  • sling:resourceType - Sempre granite/ui/components/coral/foundation/form/checkbox
  • name - Percorso JCR (usa sempre ./)
  • text - Etichetta visibile accanto al checkbox
  • value - Valore quando checked (default: {Boolean}true)

Proprietà Principali

1. Checked (Selezionato di Default)

<enabled
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    name="./enabled"
    text="Enable Feature"
    checked="{Boolean}true"
    value="{Boolean}true"/>

Quando usarlo: Feature abilitate di default che l'utente può disabilitare.


2. Value e uncheckedValue

<openInNewTab
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    name="./openInNewTab"
    text="Open in new tab"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

Importante:

  • value - Valore salvato quando checked (default: true)
  • uncheckedValue - Valore salvato quando unchecked (default: non salva nulla)

Best practice: Imposta sempre uncheckedValue="{Boolean}false" per salvare esplicitamente false!


3. Disabled

<readOnlyFlag
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    name="./readOnlyFlag"
    text="Read Only (System Managed)"
    checked="{Boolean}true"
    disabled="{Boolean}true"
    value="{Boolean}true"/>

Esempi Pratici

Esempio 1: Mostra/Nascondi Titolo

<showTitle
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    fieldLabel="Title Visibility"
    fieldDescription="Control title display"
    name="./showTitle"
    text="Show component title"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

HTL:

<h2 data-sly-test="${properties.showTitle}">
  ${properties.title}
</h2>

Esempio 2: Link in Nuova Tab

<newTab
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    name="./newTab"
    text="Open link in new tab"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

HTL:

<a href="${properties.url}"
   data-sly-attribute.target="${properties.newTab ? '_blank' : ''}"
   data-sly-attribute.rel="${properties.newTab ? 'noopener noreferrer' : ''}">
  ${properties.linkText}
</a>

Esempio 3: Abilita Animazioni

<enableAnimations
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    fieldLabel="Animations"
    name="./enableAnimations"
    text="Enable animations"
    checked="{Boolean}true"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

HTL:

<div class="component${properties.enableAnimations ? ' animated' : ''}">
  <!-- Content -->
</div>

Esempio 4: Featured Content

<isFeatured
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    fieldLabel="Featured"
    fieldDescription="Mark this content as featured"
    name="./isFeatured"
    text="Feature this content"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

Uso: Badge "Featured" nel frontend, ordinamento prioritario.


Dialog Completa con Checkbox

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
    xmlns:granite="http://www.adobe.com/jcr/granite/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="Link Component"
    sling:resourceType="cq/gui/components/authoring/dialog">
    <content
        jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/coral/foundation/container">
        <items jcr:primaryType="nt:unstructured">
            <tabs
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/tabs">
                <items jcr:primaryType="nt:unstructured">

                    <content
                        jcr:primaryType="nt:unstructured"
                        jcr:title="Content"
                        sling:resourceType="granite/ui/components/coral/foundation/container">
                        <items jcr:primaryType="nt:unstructured">

                            <!-- Link Text -->
                            <linkText
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                fieldLabel="Link Text"
                                name="./linkText"
                                required="{Boolean}true"/>

                            <!-- URL -->
                            <url
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
                                fieldLabel="URL"
                                name="./url"
                                required="{Boolean}true"
                                rootPath="/content"/>

                            <!-- Open in new tab -->
                            <newTab
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
                                name="./newTab"
                                text="Open in new tab"
                                value="{Boolean}true"
                                uncheckedValue="{Boolean}false"/>

                            <!-- Show icon -->
                            <showIcon
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
                                name="./showIcon"
                                text="Show link icon"
                                checked="{Boolean}true"
                                value="{Boolean}true"
                                uncheckedValue="{Boolean}false"/>

                        </items>
                    </content>

                </items>
            </tabs>
        </items>
    </content>
</jcr:root>

Uso in HTL

Lettura Boolean Semplice

<!-- Mostra elemento se checked -->
<div data-sly-test="${properties.showTitle}">
  <h2>${properties.title}</h2>
</div>

<!-- Aggiungi classe CSS se checked -->
<div class="component${properties.enableAnimations ? ' animated' : ''}">
  Content
</div>

<!-- Attributo condizionale -->
<a href="${properties.url}"
   data-sly-attribute.target="${properties.newTab ? '_blank' : ''}">
  Link
</a>

Con Sling Model

@Model(adaptables = Resource.class)
public class LinkModel {

    @ValueMapValue
    private String linkText;

    @ValueMapValue
    private String url;

    @ValueMapValue(name = "newTab")
    private boolean openInNewTab;

    @ValueMapValue(name = "showIcon")
    private boolean showIcon;

    public String getLinkText() {
        return linkText;
    }

    public String getUrl() {
        return url;
    }

    public boolean isOpenInNewTab() {
        return openInNewTab;
    }

    public String getTarget() {
        return openInNewTab ? "_blank" : null;
    }

    public String getRel() {
        return openInNewTab ? "noopener noreferrer" : null;
    }

    public boolean isShowIcon() {
        return showIcon;
    }

    public String getLinkClasses() {
        return showIcon ? "link link-with-icon" : "link";
    }
}

HTL con Model:

<a data-sly-use.model="com.mysite.models.LinkModel"
   href="${model.url}"
   class="${model.linkClasses}"
   data-sly-attribute.target="${model.target}"
   data-sly-attribute.rel="${model.rel}">
  ${model.linkText}
  <span data-sly-test="${model.showIcon}" class="icon"></span>
</a>

Valori Personalizzati

Esempio: Stringhe invece di Boolean

<alignment
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    name="./centerAlign"
    text="Center align content"
    value="center"
    uncheckedValue="left"/>

JCR Result:

  • Checked → centerAlign = "center"
  • Unchecked → centerAlign = "left"

HTL:

<div class="content align-${properties.centerAlign || 'left'}">
  Content
</div>

Checkbox vs Select vs Radio

Componente Uso Valori
Checkbox On/Off singolo Boolean (true/false)
Radio Scegli 1 da N opzioni Stringa (valore selezionato)
Select Scegli 1 da molte opzioni Stringa (valore selezionato)

Usa Checkbox quando: Hai una singola opzione da abilitare/disabilitare.


Problemi Comuni

❌ Problema 1: Valore non salvato quando unchecked

<!-- SBAGLIATO - unchecked non salva nulla nel JCR -->
<enabled
    name="./enabled"
    text="Enable"
    value="{Boolean}true"/>

<!-- CORRETTO - salva esplicitamente false -->
<enabled
    name="./enabled"
    text="Enable"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

Sintomo: In HTL ${properties.enabled} è null invece di false.

Soluzione: Aggiungi sempre uncheckedValue="{Boolean}false".


❌ Problema 2: Boolean senza type hint

<!-- SBAGLIATO -->
<enabled
    value="true"
    uncheckedValue="false"/>

<!-- CORRETTO -->
<enabled
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

❌ Problema 3: Checked non funziona

<!-- SBAGLIATO - checked come stringa -->
<enabled
    checked="true"/>

<!-- CORRETTO -->
<enabled
    checked="{Boolean}true"/>

❌ Problema 4: Test HTL sbagliato

<!-- RISCHIOSO - null è falsy -->
<div data-sly-test="${properties.enabled}">
  <!-- Non appare se enabled non è impostato -->
</div>

<!-- MEGLIO - confronto esplicito -->
<div data-sly-test="${properties.enabled == true}">
  <!-- Appare solo se esplicitamente true -->
</div>

<!-- OPPURE fallback nel model -->
public boolean isEnabled() {
    return enabled != null ? enabled : false;
}

Best Practices

  1. Sempre uncheckedValue: uncheckedValue="{Boolean}false"
  2. Type hints per boolean: value="{Boolean}true"
  3. Text descrittivo: "Show title" non solo "Title"
  4. fieldDescription: Spiega l'effetto del checkbox
  5. Default utili: checked="{Boolean}true" per feature abilitate di default
  6. Naming chiaro: showTitle, enableFeature, isActive
  7. Validazione in Model: Gestisci null → false
  8. Attributi condizionali: Usa operatore ternario in HTL

Pattern Avanzati

1. Checkbox con Show/Hide

<showAdvanced
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    name="./showAdvanced"
    text="Show advanced options"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

<advancedOptions
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/container"
    granite:hide="${!properties.showAdvanced}">
    <items jcr:primaryType="nt:unstructured">
        <!-- Advanced fields here -->
    </items>
</advancedOptions>

Mostra/nascondi campi basato su checkbox.


2. Multiple Checkboxes Correlate

<enableFeatureA
    name="./enableFeatureA"
    text="Enable Feature A"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

<enableFeatureB
    name="./enableFeatureB"
    text="Enable Feature B"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

<enableFeatureC
    name="./enableFeatureC"
    text="Enable Feature C"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

HTL: Combina con OR logic

<div data-sly-test="${properties.enableFeatureA || properties.enableFeatureB || properties.enableFeatureC}">
  At least one feature is enabled
</div>

Prossima Lezione

Nella prossima lezione vedremo il componente Select per dropdown con opzioni predefinite.

Risorse:


Guida #3 della serie AEM Dialog Components - ← Lezione precedente | Prossima lezione →