17

I was trying if we can validate input in javascript and then post errors on latest lightning:input. But i think it doesn't support such use case.

pattern attribute is there but it cant work when i/p is based on other fields.

The requirement I am trying to achieve is that phone number without spaces should be 11 digits.

Markup:

          <lightning:input type="tel" label="Telephone"
             name="tel" value="{!v.applicant1.Phone__c}" pattern="^[0-9_ ]*$"
             messageWhenPatternMismatch="Phone number is not valid"
             onblur='{!c.checkValidityOfphone}'
             messageWhenBadInput='Phone number should be 11 chars max'
             /> 

Controller:

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

According to the given doc, lightning:input does support client side validations. https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/js_validate_fields.htm

0

6 Answers 6

24

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.

9
  • 2
    Does the solution presented here work still? I'm trying to do some custom validation and this isn't working for me.
    – ratatoskr
    Jun 1, 2018 at 13:15
  • 1
    Hi @ratatoskr , you have to call 'inputField.showHelpMessageIfInvalid();' after setting the valid flag as false. This displays error message. I have edited the answer to reflect the same Jun 4, 2018 at 11:23
  • 2
    Thanks @PranayJaiswal, though I've tried that and still nothing. Is this working in Spring '18 orgs?
    – ratatoskr
    Jun 5, 2018 at 9:06
  • 3
    This is not working anymore. From documentation: "This validity attribute is a read-only object with the following boolean properties." Jul 23, 2018 at 15:16
  • 7
    @DanielHorký is right, this no longer works, but they gave us something very similar: reasonCmp.setCustomValidity("Error message or blank if valid"); reasonCmp.reportValidity();
    – textual
    Aug 8, 2018 at 21:40
5

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');   
        }
    }
})
3

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.

2
  • From the docs: This component supports the following methods. focus(): Sets focus on the element. setCustomValidity(): Sets the custom error message. reportValidity(): If the input is invalid, displays the error and returns false. If the input is valid, clears any displayed error and returns true. checkValidity(): Returns true if the input is valid. Jul 14, 2018 at 0:38
  • sweet, thanks for updating you answer =) +1
    – glls
    Jul 14, 2018 at 2:05
2

As of API v39.0, checking validity in lightning:input got a lot easier. Here's my controller:

({
    checkValidity : function(component, event, helper) {
        var validity = event.getSource().get("v.validity");
        console.log(validity)
    }
})

and here's my component:

<aura:component >
    <lightning:input aura:id="tel" type="tel" label="Telephone"
                     name="tel"  pattern="^[0-9_ ]*$" maxlength="11"
                     messageWhenPatternMismatch="Phone number is not valid"
                     onblur='{!c.checkValidity}'
                     /> 
</aura:component>

All you have to do is check the validity attribute of your lightning:input, and your configured error messages will appear below it automatically.

2
  • Note, Diana's answer is correct if you wanted to bring your own validation instead of use the default pattern/maxlength validation by attribute. Feb 17, 2017 at 23:30
  • But your answer perfectly suits to Present scenaio...
    – Pratap M
    May 19, 2019 at 2:25
1

I played around with Aidan's accepted answer but couldn't get the showHelpMessageIfInvalid() method to behave reliably. In my case, for some reason it would only show the error message after a user had entered their value, then tabbed off the field THEN came back to the field I was validating and attempted to tab back off again.

I did a quick debug and the validation method was firing on first input...but the error text wasn't showing up. Very frustrating. After beating my head against the proverbial SF wall, I ended up going with a completely custom route. It's a bit more work, but it's pretty reliable and arguably more flexible than the built-in SF method.

The basic idea is to have a lightning:input field and associated a lightning:formattedText field with it via aura:id. This formattedText has a css class that hides it (display:none). When the input field is filled out, onblur throws event, which you can capture. The controller captures the field that threw the event (not shown in code, but I have five or six fields that have this same validation, so I generalized it a bit). Then run your own custom validation. If the validation fails, add a "show" css class which sets the display to flex, showing the error message. Relevant code below:

Component:

<div class="slds-col slds-size_4-of-12">
                <lightning:input type="number" label="FTE" aura:id="genFTE1" step="0.01"
                                 onblur="{!c.validateFTE}"/>
                <p><lightning:formattedText aura:id="fteError" class="error-text" value="Value must be between 0 and .49" /></p>
</div>

Controller:

validateFTE : function(component, event, helper) {
        //Get field that triggered the event
        var field = component.find(event.getSource().getLocalId());
        //Get value of field
        var val = field.get("v.value");
        //Validate entry and show error message if validation is not passed
        if(val < 0 || val > 0.49) {
            $A.util.addClass(component.find("fteError"),"show");
        } else {
            $A.util.removeClass(component.find("fteError"), "show");
        }
    }

CSS:

.THIS .error-text {
    display:none;
}

.THIS .show {
    display:flex;
    color:red;
}
0

Turns out there's actually a spec for U.S. phone numbers called NANP.

So if you're looking for a more comprehensive phone number validation, you could use the following regex, which checks for stuff like extensions. The component below is based on a regex I found on Stack Overflow.

<lightning:input 
    type="tel" 
    value="{!v.someValue}" 
    aura:id="mobile" 
    name="mobile" 
    readonly="{!v.readOnly}" 
    label="Cellular Telephone Number" 
    messageWhenPatternMismatch="Please specify a valid phone format such as (###)-###-#### ext ###" 
    pattern="^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$"/>

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .