Welcome back to part 2 of the series where I build a sign-up form from start to finishing using Lightning Components.
This post we will be picking up where I left off in part 1 so if you have not done so already I encourage you to read that post first.
In part 1 we basically have a working sign-up form that allows entering multiple leads into our salesforce org. There are, however, a few items that we should add to make a better experience for the user. So today we will be adding the following:
- A spinner UI to display when saving new leads.
- Displaying better success and error messages to the user instead of using javascript alerts.
- Currently the form leaves the input fields displayed even after a creating records successfully, we will remove it from the page.
- Check for blank fields when submitting the form.
Displaying the loading spinner
Salesforce provides the lightning:spinner component for instances where your app takes a longer time to complete operations. We will be adding this to the SiteMainComp component and will be displaying it on the page each time the “Save” button is clicked.
The Component
<aura:component controller=”PublicContactFormController”>
<aura:if isTrue=”{!v.showSpinner}” aura:id=”spinnerSection”> <h1 class=”large-font”>Sign-up Form</h1> {!v.body} </aura:component> |
The spinner component is nested within an aura:if component in order to control when the spinner will be displayed onto the page. If the new attribute showSpinner is set to TRUE then the spinner will display.
Updates to Javascript Controller and Helper
We add a single line of code to the controller and helper respectively in order to render and hide the spinner component.
saveLeadsClick : function(component, event, helper){
component.set(‘v.showSpinner’, true); var leadArr = new Array();//component.get(‘v.newConts’); var totalNumOfLeads = component.get(‘v.personCnt’); for(var i = 1; i 0){ }, |
At the beginning of the saveLeadClick function in the controller we set the showSpinner attribute to true. This will display the component onto the page. We will then set the showSpinner attribute to false in the saveLeads helper function at the end of the action’s callback function where the save leads operation has completed.
saveLeads : function(cmp, leadArr) { var action = cmp.get(“c.createLeads”); action.setParams({ newLeads : leadArr }); action.setCallback(this, function(response) { if(res === ‘SUCCESS’){ } } } cmp.set(‘v.showSpinner’, false); $A.enqueueAction(action); |
Displaying Messages / Hiding Main Form
Instead of using a javascript alert box I wanted to display any success or error messages on the screen. To accomplish this we will be using the ui:message component.
The Component
<aura:component controller=”PublicContactFormController”>
<aura:if isTrue=”{!v.showSpinner}” aura:id=”spinnerSection”> <aura:if isTrue=”{!v.showMessage}” aura:id=”messageSection”> <aura:if isTrue=”{!v.showForm}” aura:id=”formSection”> {!v.body} </aura:component> |
We will add the ui:message component between the spinner and the main form section. The message will also be nested within an aura:if to control when to display a message on the page. The main form section will be nested within aura:if as well to control when to hide the page after a successful lead creation operation.
Attributes
- showMessage: Boolean value used in the aura:if with id as messageSection. If the value is TRUE the message will be displayed.
- showForm: Boolean value used in the aura:if with id as formSection. If the value to TRUE then that section will be displayed.
- message: The controller and helper functions will assign values to this attribute when the server side apex action returns either a success or error message. The attribute value will be displayed within the ui:message block.
The Code
The helper function will be modified as follows.
{ saveLeads : function(cmp, leadArr) { var action = cmp.get(“c.createLeads”); action.setParams({ newLeads : leadArr }); action.setCallback(this, function(response) { if(res === ‘SUCCESS’){ cmp.set(‘v.message’, ‘Contacts record successfully created!’); if(uiMsgCmp){ cmp.set(‘v.message’, res); if(uiMsgCmp){ } cmp.set(‘v.showSpinner’, false); $A.enqueueAction(action); |
In the callback function of the server-side action, instead of using javascript alerts to notify the user of success or error we will be setting the ui:message component values. For the success scenario, we will update the message attribute, set the showMessage and showForm attributes in order to display the message only and hide the main form section. Lastly, we will get the ui:message component by referencing it by the aura:id and setting its severity attribute to confirm so that the message block display as green (indicating success!).
If any error due occur we will perform the same actions except for not hiding the lead input sections so that the user can review any issues, storing the errors returned in response to the message attribute, and setting the severity to error.
Apex Controller
To accommodate returning error messages that are readable to the user rather than displaying the full technical exception (ie. First exception on row…) we will modify the createLeads Apex class method. I find it quite annoying when developers display everything to the end-user especially when it provides no value to them to correct any errors. I’ll usually print the full error to debug, build a utility where errors the full error logged as a custom object record or send the error via email.
In order to strip out of the message and only show the parts that the user needs to know in order to correct any mistakes I will make the following changes to the code.
@AuraEnabled public static String createLeads(List newLeads){ String msg = ”; try{ |
Instead of just returning the values of insEx.getmessage(), we’ll iterated through each dml. The DMLException class method getDmlMessage will only return the specific errors without including the full error message.
Here is what the error displays as after the above code update.
Checking for Blank Fields
In this form we will be requiring all fields to be populated with a value. To enforce this rule on the client-side we will use the following methods:
- Setting the required attribute on the lightning:input component so that each field will indicate that it needs to be completed if left blank.
- Checking each input for each PublicFormNewLead component for empty fields via the javascript controller and helper.
The Component
<aura:component > <aura:attribute name=”count” type=”Decimal” /> <aura:attribute name=”newLead” type=”Lead” default=”{‘sobjectType’:’Lead’}”/> <aura:attribute name=”showAddLeadBtn” type=”Boolean” default=”true”/> <aura:attribute name=”showRemoveLeadBtn” type=”Boolean” default=”false”/> <aura:attribute name=”showMsg” type=”Boolean” default=”false”/> <aura:attribute name=”errMsg” type=”String” /> <aura:registerEvent name=”addFormEvent” type=”c:addLeadFormEvent”/> <lightning:card > <lightning:recordEditForm objectApiName=”Lead” aura:id=”leadEdit”> </lightning:recordEditForm> <aura:if isTrue=”{!v.showAddLeadBtn}”> <lightning:button variant=”brand” label=”Add Additional Person” onclick=”{!c.fireAddFormEvent}”/> </lightning:card> </aura:component> |
To set up the PublicFormNewLeadComp component to handle blank fields validation the required attribute of each lightning input has been set to true. This will result in the field marked as red and display text notifying that the field needs to be populated.
The second item we will add is a ui:message component within the lightning card component. The message will be displayed and hidden using an aura:if checking if the attribute showMsg is TRUE. The error message will be stored in the attribute errMsg.
Javascript Controller and Helper Update for PublicFormMainComponent
Two new functions will be added to the helper and we will modify the existing controller function, saveLeadsClick.
New Function – missingInputs
missingInputs : function(lead){
if(lead.FirstName && lead.LastName && lead.Company && lead.Email && lead.Phone) |
The missingInputs helper function takes a lead object as an argument. It checks if any of the required lead fields is blank and if so returns TRUE otherwise it returns false.
Modifications to saveLeadsClick
saveLeadsClick : function(component, event, helper){
component.set(‘v.showSpinner’, true); var leadArr = new Array(); var totalNumOfLeads = component.get(‘v.personCnt’); for(var i = 1; i 0){ }, |
Originally, this function would just push all lead objects into an array and pass it into the saveLeads helper function to insert the objects as records. In the revision an additional check to validate all lead fields of are populated from all instances of the PublicFormNewLead component. If the missingInput helper function return true then we add the actual component instance to the new cmpErrArr variable, otherwise we add the lead object to the leadArr variable. Finally, at the end if we detected any instance of missing field we call the new displayErrorOnLeadForm helper function passing the component array and the main component.
New function – displayErrorOnLeadForm
displayErrorOnLeadForm : function(cmpErrArr, mainCmp){
for(var i = 0; i < cmpErrArr.length; i++){ cmpErrArr[i].set(‘v.errMsg’, ‘Please fill out all fields’); } mainCmp.set(‘v.showSpinner’, false); |
To close off this feature we will have a function that will iterate through the array of lead form components and set the error message and display the ui:message onto the page.
Summary
Here is a recap of what we were able to accomplish in today’s session.
- Display a loading screen.
- Display better messaging in the UI.
- Handle blank fields on the client-side.
I have record a video of the form in action as I did in part 1 to give you a better idea of how to new changes work. A friend of mine asked if I was going to open source this app after I published part 1 and at the time I was not sure. However, I decided that it would be the best way for someone to re-use the component and code so if you want use this with your org please check out the Github repo I created.
Thank you for reading and please leave comment if you have any feedback! Stay tuned for part 3 by following the blog or me on twitter.
One thought on “Building a Sign-up Form with Lightning Components (Part 2)”