Show custom error on lightning:input

This is a bit of an old question now, but I've discovered another way which seems pretty legit. The validity attribute of lightning:input is not just for reading the validity, you can also set it. So, write the component like this:

<aura:handler name="change" value="{!v.value}" action="{!c.valueChangeValidation}"/>

<lightning:input aura:id="inputField" 
                 type="text" value="{!v.value}" 
                 label="Enter foo" 
                 messageWhenBadInput="You must say foo" />

And then the controller like this:

valueChangeValidation : function(component, event, helper) {
    var inputField = component.find('inputField');
    var value = inputField.get('v.value');
    if(value != 'foo') {
        inputField.set('v.validity', {valid:false, badInput :true});
        inputField.showHelpMessageIfInvalid();

    }
}

Then, you can write whatever logic you want in that handler method and the result is shown in the normal Lightning way.


I noticed a few issues:

  • v.errors is not available in lightning:input though it's available in ui:input. So you'll want to define the errors attribute in your component and iterate over it to display the errors.
  • event.getSource().get('v.value') won't give you the input value here. You can use component.find("tel").get("v.value") instead.

Here's the revised code (I removed value="{!v.applicant1.Phone__c} when testing in my org):

<aura:component >
<aura:attribute name="errors" type="List"/>
<lightning:input aura:id="tel" type="tel" label="Telephone"
         name="tel"  pattern="^[0-9_ ]*$"
         messageWhenPatternMismatch="Phone number is not valid"
         onblur='{!c.checkValidityOfphone}'
         messageWhenBadInput='Phone number should be 11 chars max'
         /> 
<aura:iteration items="{!v.errors}" var="error">{!errors}</aura:iteration>

({
    checkValidityOfphone : function(component, event, helper) {
        console.log('checkValidityOfphone called');
        //var inp = event.getSource();
        var val=component.find("tel").get('v.value');
        val=val.replace(/ /g,'');
        console.log(val);
        console.log(val.length);
        if(val.length!=11){
            component.set("v.errors", ["Input not a number: " + val]);
            console.log('Error Set called');   
        }
    }
})

There's a new method on lightning:input named reportValidity() that simplifies validation. The docs describe this method as doing the following:

If the input is invalid, displays the error and returns false. If the input is valid, clears any displayed error and returns true.

Here's a link to the full documentation and you should look for the Input Validation section: https://developer.salesforce.com/docs/component-library/bundle/lightning:input/documentation

Here's an example of how to use this:

const inputField = component.find('input-field-aura-id');
if(inputField.reportValidity()) {
    component.set('v.attributeName', inputField.get('v.value'));
}

I suggest using reportValidity() because it does all the work for you. The other way to do this (described in other answers) is to get a component's validity attribute, check if the valid property is true and if it is, calling showHelpMessageIfInvalid() to display an error message.