Custom validation with lightning:recordEditForm

Lightning:recordEditForm is a very helpful lightning component that allows us to create editable fields based on the Salesforce object definition. Can be used to create or edit object whose fields by default inherits all standard validation. I am not going to rewrite documentation here so if you want to learn more about this component, you can check out this link. Instead of this, I want to focus on some corner cases, when we don’t want to define fields as universal required or use validation rules. These situations require from us additional code to implement custom validation.

So, let’s take a look at code we need to implement it and follow the most important lines in this (These are also marked in code).

testComponent.cmp

<aura:component description="testComponent" implements="force:lightningQuickAction">
    <aura:attribute name="loading" type="Boolean" default="false" />
    <aura:attribute name="closeDate" type="Date"/>
	<aura:handler name="init" value="{!this}" action="{!c.init}"/>
    <lightning:recordEditForm
        objectApiName="Opportunity"
        aura:id="recordEditFormForNewOpportunity"
        onsuccess="{!c.handleSuccess}"
        onsubmit="{!c.handleSubmit}"
        onerror="{!c.handleError}"
        onload="{!c.handleLoad}">
        <lightning:messages aura:id="OppMessage" />
        <div class="slds-p-horizontal_medium">
            <span>
                <lightning:inputField fieldName="Name" aura:id="newOpportunityField" class="slds-form-element_stacked"/>
            </span>
            <span>
                <lightning:inputField fieldName="StageName" aura:id="newOpportunityField" class="slds-form-element_stacked"/>
            </span>
            <span>
                <lightning:inputField fieldName="CloseDate" aura:id="newOpportunityField" value="{!v.closeDate}" class="slds-form-element_stacked"/>
            </span>
            <span class="input-container">
                <span class="asterix">*</span>
                <lightning:inputField fieldName="Amount" aura:id="newOpportunityField" class="slds-form-element_stacked requiredField"/>
            </span>
        </div>
        <div class="slds-m-top_medium slds-text-align_center">
            <lightning:button
                type="submit"
                label="Submit"
                variant="brand">
            </lightning:button>
        </div>
        <aura:if isTrue="{!v.loading}">
        	<lightning:spinner alternativeText="Loading" />
    	</aura:if>
    </lightning:recordEditForm>
</aura:component>
  • 1 line: We implement here “force:lightningQuickAction” because with want to test our component with Quick Action on Opportunity object. (It is not necessary at all)
  • 5 line: Here we start to define our lightning:recordEditForm, we need to set up here controller methods for “onsubmit” and “onsuccess” events but it is strongly recommended to set up also behavior for “onerror” and “onload” events
  • 12 line. <lightning:messages> is a component that we use to display validation messages to the user.
  • 14-26 line. We use <lightning:inputField> to set up fields that we want to show to the user. Especially let’s take a look at two things: last one lightning:inputField and note that it has additional css class “requiredField” before it we have a <span> tag with content inside. This is our custom require mark which tells the user that this field is required, we will style this sign later is our style class. In addition, closeDate field has set “value” parameter, which we will need later.
  • 29 line. We need to create only the submit button (not cancel) because salesforce quick actions implement cancel behavior by default.
  • 36 line. <lightning:spinner> is used to stop user from doing actions when our component is waiting for a response.

testComponentContoller.js

({
    init: function (component, event, helper) {
        component.set('v.loading', true);
    },

    handleSuccess: function (component, event, helper) {
        $A.get("e.force:closeQuickAction").fire();
        $A.get('e.force:showToast').setParams({
            "title": "Success",
            "message": "Record has been saved!",
            "type": "success",
        }).fire();
    },

    handleError: function (component, event, helper) {
        component.set('v.loading', false);
        component.find('OppMessage').setError('Undefined error occured');
    },

    handleLoad: function(component, event, helper) {
        component.set('v.loading', false);
    },

    handleSubmit: function(component, event, helper) {
        event.preventDefault();
        helper.handleFormSubmit(component);
    }
})
  • 3 line. We set up “loading” attribute when we know that component waits for a response from Server. Every time we get the answer we need to set this attribute to ”false”
  • 7 line. Built-in aura event “force:closeQuickAction” is used to close quick action modal after successfully record save/update.
  • 8 line. Built-in aura event “force:showToast” is used to notify user about successfully record save/update.
  • 25-26 lines. Here we need to prevent default behaviour of <lightning:recordEditForm> and run the function from helper, to perform our custom validation logic.

testComponentHelper.js

({
    handleFormSubmit: function(component) {
        var showValidationError = false;
        var fields = component.find("newOpportunityField");
        var vaildationFailReason = '';
        var currentDate = new Date().toJSON().slice(0,10);

        fields.forEach(function (field) {
            if(field.get("v.fieldName") === 'Amount' && $A.util.isEmpty(field.get("v.value"))){
                showValidationError = true;
                vaildationFailReason = "The field 'Amount' cannot be empty!";
            } else if (field.get("v.fieldName") === 'StageName' && field.get("v.value") === 'Prospecting' && component.get("v.closeDate") < currentDate) {
                showValidationError = true;
                vaildationFailReason = "Close Date cannot be earlier  earlier than today if Stage is 'Prospecting'!";
        	}
        });
        
        if (!showValidationError) {
            component.set('v.loading', true);
            component.find("recordEditFormForNewOpportunity").submit();  
        } else {
            component.find('OppMessage').setError(vaildationFailReason);
            component.set('v.loading', false); 
        }
    },
})
  • 4 line. Collect and assign to variable all <lightning:inputField> items.
  • 8-16 lines. That’s where all “magic” happens. We iterate over fields and define validation criteria for every we want, we can do it because of every lightning:inputField contains the name of the field and value of it. In this case, our validation checks two criteria: “Amount” field cannot be empty and also if the value of the “Stage Name” field is set up to “Prospecting” then “Close Date” cannot be set as earlier than today. If validation is failed, then we set the variable “showValidationError” to the appropriate status and also define an error message for User.
  • 20 line. In the case of no validation errors, we can submit a record to save.
  • 22 line. In this line, if there are some validation errors we can display an error message to the user. Just remember that it is strongly recommended to keep an error message in custom labels.

testComponent.css

.THIS {
}

.THIS .asterix{
    position: absolute;
    top: 4%;
    font-size: 15px;
    color: #da1d1d;
    left: 5px;
}

.THIS .requiredField .slds-form-element__label{
    margin-left: 9px;
}
  • In our custom css styles, we define a proper appearance of custom require field sign

Before we test our component, we need to create a quick action on the contact object and include it on the proper page layout, so let’s do it.

Now we can finally test our form, so to do it let’s go to one of our contacts and click addOpportunity button:

Now we can put a wrong data to fire our custom validation….

….. and Voila! Both rules work as designed. Take a look also on require sign before Amount field, it is almost identical to built-in standard required marks.

Summarize, the above code is a nice trick to ensure that our data is valid, but be aware that it’s a very basic example and you can modify very much your own code, especially I recommend to use a custom apex controller to get necessary fields from fieldSet instead of hardcoding them. Anyway, I hope that you found here useful tips.

See you next time. Have fun!

Resource

5 1 vote
Article Rating
Subscribe
Notify of
guest
6 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
trackback

[…] you liked it, then maybe you want to take a look on our other solutions: for example: Custom Validation or how to automatically refresh your record […]

trackback

[…] the other hand you can take a look how to create simple validation for you data in recordEditForm here or how to refresh data on record page by clicking […]

Jenil
Jenil
1 year ago

Hi, I have used this approach, but even if I have event.preventDefault() mentioned in case of error, it still save the record with the data. Any idea why it would do that?

Thanks.

trackback

[…] However remember that you can customize this code in many ways, for example,you can check this article where we do custom validation for similar component in Aura Components, which after small […]

trackback

[…] action (If you want to learn more about building fully customized and validated quick action-click here). If everything works fine you should get a success toast message, notice that message contains […]

Close Menu
6
0
Would love your thoughts, please comment.x
()
x