Expand my Community achievements bar.

Don’t miss the AEM Skill Exchange in SF on Nov 14—hear from industry leaders, learn best practices, and enhance your AEM strategy with practical tips.
SOLVED

How to require one of two fields in dialog to be completed?

Avatar

Level 5

We have a component with icons links and each icon needs to have one of the following two fields completed:

  • internalLink
  • externalLink

Currently, authors can leave them both blank, which causes a broken link to a non-existent page. How can I write a validation rule that notifies the users that one of the two fields is required?

<internal-link
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
    fieldDescription="Select internal link"
    fieldLabel="Internal Link"
    name="./internalLink"
    rootPath="/content/attbusiness/en"/>
<external-link
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
    fieldDescription="Link to external page outside"
    fieldLabel="External link"
    name="./externalLink"/>

 

Topics

Topics help categorize Community content and increase your ability to discover relevant content.

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Hi @Codelime ,


there isn't an out-of-the-box JCR property or mechanism to enforce validation rules like "at least one of two fields must be filled"

But

 

you can make use of ExtraClientlibs, a sample js here:

(function () {
    "use strict";

    // Function to validate fields
    function validateLinks() {
        var internalLink = document.querySelector('coral-pathfield[name="./internalLink"]').value.trim();
        var externalLink = document.querySelector('coral-textfield[name="./externalLink"]').value.trim();

        if (!internalLink && !externalLink) {
            alert("Error: At least one of the fields (Internal Link or External Link) is required.");
            return false; // Prevent dialog submission
        }
        return true; // Allow dialog submission
    }

    // Add event listener to dialog submit button
    document.addEventListener("foundation-contentloaded", function () {
        var dialog = document.querySelector(".cq-dialog");
        if (dialog) {
            var submitButton = dialog.querySelector(".cq-dialog-submit");
            if (submitButton) {
                submitButton.addEventListener("click", function (event) {
                    if (!validateLinks()) {
                        event.preventDefault(); // Prevent dialog submission
                    }
                });
            }
        }
    });
})();

Thank you.

-Sravan

View solution in original post

3 Replies

Avatar

Correct answer by
Community Advisor

Hi @Codelime ,


there isn't an out-of-the-box JCR property or mechanism to enforce validation rules like "at least one of two fields must be filled"

But

 

you can make use of ExtraClientlibs, a sample js here:

(function () {
    "use strict";

    // Function to validate fields
    function validateLinks() {
        var internalLink = document.querySelector('coral-pathfield[name="./internalLink"]').value.trim();
        var externalLink = document.querySelector('coral-textfield[name="./externalLink"]').value.trim();

        if (!internalLink && !externalLink) {
            alert("Error: At least one of the fields (Internal Link or External Link) is required.");
            return false; // Prevent dialog submission
        }
        return true; // Allow dialog submission
    }

    // Add event listener to dialog submit button
    document.addEventListener("foundation-contentloaded", function () {
        var dialog = document.querySelector(".cq-dialog");
        if (dialog) {
            var submitButton = dialog.querySelector(".cq-dialog-submit");
            if (submitButton) {
                submitButton.addEventListener("click", function (event) {
                    if (!validateLinks()) {
                        event.preventDefault(); // Prevent dialog submission
                    }
                });
            }
        }
    });
})();

Thank you.

-Sravan

Avatar

Level 6

Hi @Codelime, there's no need to make two seperate link fields for external and internal. You can use pathfield for external links as well. Just copy paste the external URL in the pathfield and it will work fine.
Using the required = "{Boolean}true" will make the field mandatory. Please find the below code for the same:

 

 

<any-link
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
    fieldDescription="Select link"
    fieldLabel="Link"
    name="./Link"
    rootPath="/content/attbusiness/en"/
    required="{Boolean}true">

 

 


If you still insist on adding two fields for external and internal links then you have to write your own custom logic in JS for the same.
Please refer the below link to see the examples for how to apply JS on dialog fields:
https://lucanerlich.com/docs/aem/dialog-validation/

Avatar

Community Advisor

Hi @Codelime ,

 

HI @Codelime ,

To enforce that one of the two fields (internalLink or externalLink) must be completed in your AEM dialog using Java, you can implement a custom validator. Here's how you can achieve this:

  1. Create a Java class to implement the validator:

 

package com.example.core.validation;

import com.adobe.granite.ui.components.Value;
import com.adobe.granite.ui.components.ValueMap;
import com.adobe.granite.ui.validation.AbstractValidator;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.ValueMap;

import java.util.List;

public class RequiredFieldValidator extends AbstractValidator {
    
    @Override
    public String getFieldName() {
        return "internalLinkOrExternalLink";
    }

    @Override
    public boolean isValid(ValueMap properties) {
        String internalLink = properties.get("internalLink", String.class);
        String externalLink = properties.get("externalLink", String.class);
        
        return StringUtils.isNotBlank(internalLink) || StringUtils.isNotBlank(externalLink);
    }

    @Override
    public String getErrorMessage() {
        return "Please fill in either the Internal Link or External Link field.";
    }
}
​

 

    1. Register the validator as an OSGi service:

 

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:primaryType="sling:OsgiConfig"
    service.pid="com.example.core.validation.RequiredFieldValidator"
    sling.servlet.resourceTypes="cq/gui/components/authoring/dialog"
    sling.servlet.selectors="validator"
    sling.servlet.extensions="json"
    sling.servlet.methods="GET"/>
​

 

  • Apply the validator to your dialog:

 

<yourComponent
    jcr:primaryType="nt:unstructured"
    sling:resourceType="cq/gui/components/authoring/dialog">
    <content jcr:primaryType="nt:unstructured">
        <items jcr:primaryType="nt:unstructured">
            <internal-link
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
                fieldDescription="Select internal link"
                fieldLabel="Internal Link"
                name="./internalLink"
                rootPath="/content/attbusiness/en"/>
            <external-link
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                fieldDescription="Link to external page outside"
                fieldLabel="External link"
                name="./externalLink"/>
        </items>
    </content>
    <listeners jcr:primaryType="nt:unstructured"/>
    <validators jcr:primaryType="nt:unstructured">
        <internalLinkOrExternalLink
            jcr:primaryType="nt:unstructured"
            sling:resourceType="granite/ui/components/coral/foundation/clientlibs"
            fieldDescription="Internal Link or External Link"
            allowEmpty="{Boolean}false"/>
    </validators>
</yourComponent>
​

 

With this implementation, when the dialog is submitted, the validator checks if either the internalLink or externalLink field is filled. If neither field is filled, it returns an error message, and the dialog submission is prevented. Adjust the error handling and messaging as needed to fit your requirements.