Custom Validation in a Lightning Input Field Component

This is a simple example to validate lightning input fields in a lightning component.

Three main seeded functions are used for the custom validation in input components.

  • reportValidity
  • setCustomValidity
  • checkValidity

The report validity uses to displays the error message on the invalid fields. The error message are defined based on the pattern mismatch, required, max length, min length, etc. attributes. The custom error message for the mentioned attributes can be defined in the corresponding messageWhenPatternMismatch, messageWhenTypeMismatch, messageWhenValueMissing, etc error message attributes.

All input component type has a validity attribute which is a readonly object with the following attributes.

  • badInput: Indicates that the value is invalid.
  • customError: Indicates that a custom error has been set. See Custom Validity Error Messages.
  • patternMismatch: Indicates that the value doesn’t match the specified pattern.
  • rangeOverflow: Indicates that the value is greater than the specified max attribute.
  • rangeUnderflow: Indicates that the value is less than the specified min attribute.
  • stepMismatch: Indicates that the value doesn’t match the specified step attribute.
  • tooLong: Indicates that the value exceeds the specified maxlength attribute.
  • tooShort: Indicates that the value is less than the specified minlength attribute.
  • typeMismatch: Indicates that the value doesn’t match the required syntax for an email or url input type.
  • valueMissing: Indicates that an empty value is provided when required attribute is set to true
  • valid: True if none of the preceding properties are true.

The report validity function throws the corresponding error message based on the v.validity attribute value.

handleBlur: function (cmp, event) {
    var validity = cmp.find("myinput").get("v.validity");
    console.log(validity.valid); //returns true
}

SetCustomValidity method can be used to set the custom error message dynamically from the code based on certain conditions.

({
    register : function(component, event) {
        var inputCmp = component.find("inputCmp");
        var value = inputCmp.get("v.value");
        // is input valid text?
        if (value === "John Doe") {
            inputCmp.setCustomValidity("John Doe is already registered");
        } else {
            inputCmp.setCustomValidity(""); // if there was a custom error before, reset it
        }
        inputCmp.reportValidity(); // Tells lightning:input to show the error right away without needing interaction
    }
})

CheckValidity is the another seeded method which returns a boolean value based on the valid property in the validity attribute. The value only be true if the none of the error conditions are met.

https://developer.salesforce.com/docs/component-library/bundle/lightning:input/specification

Go through the link for more details on the custom error message attributes in input component.

In the below example, I have included the best options to use the standard validations and the custom validations by separating the layout into different sections.

The first section contains three input components for first name , last name and email with same aura id. The submit button handler checks the validity of each component registered in the aura id named ‘field’. Reduce is standard Javascript array function that reduces the array values into a single output values based on the defined callback. Also, the function has two parameters, one is a callback (reducer) which execute over each array element and other is an initial value.

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes" access="global" &gt;
    <div class="c-container"&gt;
        <lightning:layout multipleRows="true"&gt;
            <lightning:layoutItem padding="around-small" size="5"&gt;
                <lightning:layout multipleRows="true"&gt;
                    <lightning:layoutItem padding="around-small" size="12"&gt;
                        <lightning:input aura:id="field" label="First name" placeholder="First name" required="true" messageWhenValueMissing="Enter First Name" /&gt;
                    </lightning:layoutItem&gt;
                    <lightning:layoutItem padding="around-small" size="12"&gt;
                        <lightning:input aura:id="field" label="Last name" placeholder="Last name" required="true"  /&gt;
                    </lightning:layoutItem&gt;
                    <lightning:layoutItem padding="around-small" size="12"&gt;
                        <lightning:input aura:id="field" type="email" label="Email Address" placeholder="Email Address" required="true"  messageWhenTypeMismatch="Enter a valid email address"/&gt;
                    </lightning:layoutItem&gt;
                    <lightning:layoutItem padding="around-small" &gt;
                        <lightning:button aura:id="submit" type="submit" label="Submit" onclick="{! c.onClick }" /&gt;
                    </lightning:layoutItem&gt;
                </lightning:layout&gt;
            </lightning:layoutItem&gt;
            <lightning:layoutItem padding="around-small" size="1"&gt;
            </lightning:layoutItem&gt;
            <lightning:layoutItem padding="around-small" size="5"&gt;
                <lightning:layout multipleRows="true"&gt;
                    <lightning:layoutItem padding="around-small" size="12"&gt;
                        <lightning:input aura:id="firstName" label="First name" placeholder="First name"/&gt;
                    </lightning:layoutItem&gt;
                    <lightning:layoutItem padding="around-small" size="12"&gt;
                        <lightning:input aura:id="lastName" label="Last name" placeholder="Last name" required="true"  /&gt;
                    </lightning:layoutItem&gt;
                    <lightning:layoutItem padding="around-small" size="12"&gt;
                        <lightning:input aura:id="email" type="text" label="Email Address" placeholder="Email Address" required="true"  messageWhenPatternMismatch="Enter a valid email address" pattern="^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$"/&gt;
                    </lightning:layoutItem&gt;
                    <lightning:layoutItem padding="around-small" size="12"&gt;
                        <lightning:input aura:id="phone" type="text" label="Phone Number" placeholder="Phone Number" required="true"/&gt;
                    </lightning:layoutItem&gt;
                    <lightning:layoutItem padding="around-small" &gt;
                        <lightning:button aura:id="submit" type="submit" label="Submit Custom Validation" onclick="{! c.onCustomValidationClick }" /&gt;
                    </lightning:layoutItem&gt;
                </lightning:layout&gt;
            </lightning:layoutItem&gt;
        </lightning:layout&gt;
        
    </div&gt;
</aura:component&gt;

Here, In the onClick handler method, the reduce function iterates over components which is having id value as field. The initial value of the function is set as true and the callback accumulate all components validity into a single boolean output. More details on reduce function is provided on the last.

({
	onClick : function(component, event, helper) {
	//Validating all input fields together by providing the same aureid 'field'	
        let isAllValid = component.find('field').reduce(function(isValidSoFar, inputCmp){
            //display the error messages
            inputCmp.reportValidity();
            //check if the validity condition are met or not.
            return isValidSoFar && inputCmp.checkValidity();
        },true);
	},
    
    onCustomValidationClick : function(component, event, helper) {
        //Explicitly checking the custom validation: 
        var phoneCmp = component.find('phone');
       	var phoneCmpValue = phoneCmp.get("v.value");
        //Custom regular expression for phone number
        var phoneRegexFormat = /^\d{10}$/;
        //Check for regular expression match with the field value
        if(!phoneCmpValue.match(phoneRegexFormat)) {
           //set the custom error message
            phoneCmp.setCustomValidity("Enter valid phone number");
        }else{
           //reset the error message
            phoneCmp.setCustomValidity("");
        }
        //Group all the fields ids into a JS array
        var controlAuraIds = ["firstName","lastName","email","phone"];
       //reducer function iterates over the array and return false if any of the field is invalid otherwise true.
        let isAllValid = controlAuraIds.reduce(function(isValidSoFar, controlAuraId){
           //fetches the component details from the auraId
            var inputCmp = component.find(controlAuraId);
           //displays the error messages associated with field if any
            inputCmp.reportValidity();
           //form will be invalid if any of the field's valid property provides false value.
            return isValidSoFar && inputCmp.checkValidity();
        },true);
        
        
    }
})

onCustomValidationClick handler method checks the validity of fields those are having different aura Id. Also, included a custom phone number validity check using regular expression in the controller side which is not configurable in the html side.

As you can see in the below image, the errors are shown based on the validation defined in the standard validation and the custom validation in the JS side.

https://github.com/anilsomasundaran/Lightning-Input-Field-Validation/tree/master/CustomValidation

How reduce() works

[0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array) {
  return accumulator + currentValue;
});

The callback would be invoked four times, with the arguments and return values in each call being as follows:

callbackaccumulatorcurrentValuecurrentIndexarrayreturn value
first call011[0, 1, 2, 3, 4]1
second call122[0, 1, 2, 3, 4]3
third call333[0, 1, 2, 3, 4]6
fourth call644[0, 1, 2, 3, 4]10
Advertisements

2 thoughts on “Custom Validation in a Lightning Input Field Component

  1. perfect73 July 18, 2019 / 1:30 pm

    Thanks man, can this work for lightning:inputField

    Like

    • Anil Somasundaran July 29, 2019 / 5:25 pm

      yes

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s