SFDC Stop - Always the latest about Salesforce


Full Tutorial Series with videos, free apps, live sessions, salesforce consulting and much more.


Telegram logo   Join our Telegram Channel

Saturday, 31 March 2018

Salesforce Lightning Events Part 1 - Component Events Introduction

A component event is fired from the instance of a component. It can be handled either by the component who has fired this event or any other component in the hierarchy that receives the component event and has a handler defined to handle that component event.

Propagation of Component Event

There are mainly two phases in component event propagation :-
  1. Bubble Phase
  2. Capture Phase

Bubble Phase

In this phase, when an event is fired, it'll traverse up in the hierarchy and will end at the application root. In this phase, any component in the hierarchy in which we have defined a handler for that event can handle that event or even stop it from propagating further towards application root.
In this phase, the event traverses from source component to top by traversing the components in hierarchy and will stop finally at the application root. The source component who fired the event, can easily handle that event without any restrictions as the propagation starts from itself.

Component Event Propagation in Bubble Phase

Capture Phase

In this phase, when an event is fired, it'll move directly to the application root and then from the application root it will move through the path that ends at the component who fired this event. While traversing this path, any other component in which we have defined a handler for that event can handle that event and even stop that event from propagating further in the hierarchy.
In this phase, the event traverses directly from source component to top and then move towards bottom by traversing the components in hierarchy back to source component. The event cannot be handled by the source component which fired the event if it's propagation is stopped by any other component in the hierarchy while traversing down from application root to source component.

Component Event Propagation in Capture Phase

By default, the component events traverse in Bubble Phase.

In this post, you learned about the Component Events in lightning. You got answers to queries like:- What are component events ?  How these events propagate through our application ? Which path they follow ? In the next post, we are going to jump on to code to see a live demo of Component Events in Lightning and there will be a youtube video too showing the whole demo which I'll upload to SFDC Stop Youtube Channel. You can directly go to the next post by clicking here. Stay tuned and post your feedback in the comments section below. Also share this blog if you liked it.
Happy Trailblazing..!!

Sunday, 25 March 2018

Events in Salesforce Lightning - Introduction

What is an Event ? Generally an event is a thing that happens or takes place. When we talk about events in JavaScript, they are simply a thing that happen to HTML element. There can be various types of events when we talk about HTML. For example:-
  1. Web page loaded is an event
  2. Clicking of a button is an event
  3. Changing text in an input field is also an event

So, we can say that any kind of interaction that happen in a webpage either automatically or by human interaction is an event. Now talking about the Salesforce Events, basically there are 2 types of events in Salesforce:- 
  1. Component Events
  2. Application Events

Component Events

A component event is an event that is fired by a lightning component. A component event can either be handled by the component itself or it can be handled by any other component which is present in the hierarchy that receives the event.

Application Events

An application event is generally like a broadcast message. Like if you send a broadcast, then all the receivers that are configured to accept that broadcast message receive that message. Similarly, an application event is fired by a component and all the other components that have the handler defined to receive that event are notified when the event is fired. Application Events are not bound by any hierarchy or relationship.

Salesforce recommends to use component events whenever possible as they have a limited scope. Application Events are handled at the application level and can be used to communicate between different components that are not related to each other.

Usually, we deal with the events that are fired when the user interacts with the browser. Such events are known as browser events. There are another type of events that are called system events that automatically trigger during the component life cycle. If you remember the Salesforce Lightning Tutorial Series, in first video, we added an init handler in our lightning component as shown below:-

In the above code snippet, you can see that I made a handler which runs when the component is initialized and i.e why salesforce has defined it to give the name init and in the above case, it calls the getContactList function which is present in our lightning controller. As we wanted to fetch our contact list when the page is loaded in the previous tutorial, so we used an init handler to do the task. Such event which is fired automatically on component initialization is an example of system event.

So, this was the introduction in which you learnt about what events are and how many events are there in Salesforce Lightning. In the next post, you'll learn about Component Events in Salesforce Lightning. You can go to the next post directly by clicking here. Otherwise you can directly jump on to any other tutorial from the below tutorials in the Salesforce Lightning Events Tutorial Series:-
  1. Salesforce Lightning Events Part 1 - Component Events Introduction
  2. Salesforce Lightning Events Part 2 - Building Component Events
  3. Salesforce Lightning Events Part 3 - Bubble and Capture Phase
  4. Salesforce Lightning Events Part 4 - Understanding Container Components
  5. Salesforce Lightning Events Part 5 - Application Events Introduction
  6. Salesforce Lightning Events Part 6 - Building Application Events
  7. Salesforce Lightning Events Part 7 - Phases of Application Events
Here is the playlist on YouTube that you can follow along with the blogs to have a better understanding:-


So stay tuned and subscribe to my blog if you liked it and do comment your feedback in comments.
Happy Trailblazing..!!

Tuesday, 20 March 2018

sObject Convertor - A utility application to convert records from one sObject to another


What is sObject Convertor ?

Recently, SFDC Stop crossed 100 Subscribers on Youtube. Thank you everyone for supporting and encouraging me to do more for the community. As a gift to all, I have made a utility application - sObject Convertor using which you can convert records from one sObject to another. 


How can I install sObject Convertor ?

Follow these steps to install sObject Convertor application in your own salesforce org:- 
  • Go to the deployment section of the github repository and click on Deploy to Salesforce button which looks like this:-
  • You'll be taken up to the github salesforce deploy tool. Click on Login to Salesforce button on the top right corner.
  • The tool will ask for permissions, click allow.
  • After giving the permissions, you'll have a screen like this:- 
  • Click on deploy button in the top right corner and all the code will be deployed directly to your salesforce org.
  • Now, go to your org homepage or any detail page where you want to embed this app as a lightning component.
  • Click on the Settings (gear) icon and click on Edit Page.
  • Search for lightning component named SObjectConvertor in the left search box.
  • Drag and drop the SObjectConvertor lightning component to your page layout.
  • Click on save and click on assign as org default (if needed). Click on back button, left from the top right corner and you'll be back to your page with the lightning component embedded into it.

Instructions for using the application

  1. Choose the source object and the destination object.
  2. Search for the records of source object.
  3. Click on add record button as you search for each record to add the record in the list of records to be converted.
  4. To define the sobject mapping you have two options:-
    1. Create a new mapping:- In this case, you have to manually click add row for each field in which you have to map a field of source sObject to a field of destination sObject.
    2. Choose an existing mapping:- In this case, you can choose the previously saved mapping and the field mapping rows will be auto populated.
  5. If you have created a mapping, you can save that mapping by clicking on Save Mapping button and then giving the name of mapping in the dialog that appears. This mapping can then be used in future.
  6. Click on convert records button.

Your records will be converted and there are two different sections for success and failures. In the success section, you'll have the ids of the source and the destination sObject records. Whereas in the failure section, you'll have the id of the source sObject record with the particular error message due to which that record is not converted.

Tired of reading or just scrolled down..!! Don't worry, you can watch the video too.



So, that's all for this application. If you liked it then do show your support by giving a  Star  and   Fork  the Github Repository to contribute. If you face any issues in the app, do report those by creating an issue here. If you want to contribute in this project, you can refer to the README file for the to-do tasks which are to be implemented in this applications. Do give your suggestions in the comments section below.
Happy Trailblazing..!!

Friday, 2 March 2018

Salesforce Lightning Tutorial - Part 5 | Adding Validations

Welcome to the 5th tutorial in the Salesforce Lightning Tutorial Series. In this post, you'll learn about how you can validations in custom lightning component. I'll be extending the code used in my previous posts so, if you are just starting or need to learn only about applying validations only do have a look at my previous posts or at least the code by having a look at my blog posts starting from here or my github repository code in create branch here so that you can understand the progress till now and the further additions that I'll do in this post.

So, let's begin by adding validations in our Lightning Component. Here our main focus is on client side validations only so all this validation part will be handled by making changes only in the Lightning Component and the Lightning Controller.

1. Lightning Component

Let's have a look at the code below and then I'll highlight the changes.
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" controller="ContactListController" access="global">
    <!-- Handler to call function when page is loaded initially -->
    <aura:handler name="init" action="{!c.getContactsList}" value="{!this}" />
    <!-- List of contacts stored in attribute -->
    <aura:attribute name="contactList" type="List" />
    <!-- New Contact Object -->
    <aura:attribute name="contact" type="Contact"
    default="{
        'SObjectType': 'Contact',
        'FirstName': '',
        'LastName': '',
        'Email': '',
        'Phone': ''
    }">            
    </aura:attribute>
    <!-- Method to validate new contact -->
    <aura:method name="validateContact" action="{!c.validateContact}" />
    <!-- Lightning card to show contacts -->
    <lightning:card title="Contacts">
        <!-- Body of lightning card starts here -->
        <p class="slds-p-horizontal_small">
            <!-- Aura iteration to iterate list, similar to apex:repeat -->
            <div aura:id="recordViewForm">
                <aura:iteration items="{!v.contactList}" var="contact">
                    <!-- recordViewForm to view the record -->
                    <lightning:recordViewForm recordId="{!contact.Id}" objectApiName="Contact">
                        <div class="slds-box slds-theme_default">
                            <!-- inputfield checkbox used to check wether to delete the contact or not -->
                            <lightning:input type="checkbox" value="{!contact.Id}" label="Mark for Deletion" aura:id="deleteContact" />
                            <br />
                            <!-- outputfield used to output the record field data inside recordViewForm -->
                            <lightning:outputField fieldName="FirstName" />
                            <lightning:outputField fieldName="LastName" />
                            <lightning:outputField fieldName="Email" />
                            <lightning:outputField fieldName="Phone" />
                        </div>
                    </lightning:recordViewForm>
                    <!-- Line break between two records -->
                    <br />
                </aura:iteration>
            </div>
            <div aura:id="recordEditForm" class="formHide">
                <aura:iteration items="{!v.contactList}" var="contact">
                    <div class="slds-box slds-theme_default">
                        <!-- inputfield used to update the record field data -->
                        <lightning:input value="{!contact.FirstName}" />
                        <!-- Validation added -->
                        <lightning:input aura:id="fieldToValidate" value="{!contact.LastName}" messageWhenValueMissing="Contact's Last Name is Mandatory" required="true"/>
                        <lightning:input type="email" value="{!contact.Email}" />
                        <!-- Validation added -->
                        <lightning:input aura:id="fieldToValidate" messageWhenPatternMismatch="Please enter the number in this pattern - (XXX) XXX-XXXX" type="tel" value="{!contact.Phone}" pattern="\([0-9]{3}\) [0-9]{3}-[0-9]{4}" />
                    </div>
                    <br />
                    <!-- Line break between two records -->
                </aura:iteration>
            </div>
        </p>
        <!-- Lightning card actions -->
        <aura:set attribute="actions">
            <!-- New contact modal button added -->
            <lightning:button name="contactModal" label="New Contact" onclick="{!c.openModal}" />
            <!-- Delete button added -->
            <lightning:button variant="destructive" label="Delete" onclick="{!c.deleteContacts}" />
            <!-- New button added -->
            <lightning:button label="New" onclick="{!c.newContact}" />
            <!-- Edit/Save button added -->
            <lightning:button variant="brand" label="Edit" name="edit" onclick="{!c.editContacts}" />
        </aura:set>
    </lightning:card>
    <!-- Contacts Modal Section -->
    <div>
        <section aura:id="contactModal" role="dialog" tabindex="-1" aria-labelledby="contactModalHeading" aria-modal="true" aria-describedby="contactModalBody" class="slds-modal">
            <!-- Modal Container -->
            <div class="slds-modal__container">
                <!-- Modal Header ( consists of close button and heading of modal ) -->
                <header class="slds-modal__header">
                    <lightning:buttonIcon class="slds-modal__close" alternativeText="Close" iconName="utility:close" onclick="{!c.closeModal}" variant="bare-inverse" size="large"></lightning:buttonIcon>
                    <h2 id="contactModalHeading" class="slds-text-heading_medium slds-hyphenate">New Contact</h2>
                </header>
                <!-- Modal Body ( consists of form ) -->
                <div class="slds-modal__content slds-p-around_medium" id="contactModalBody">
                    <!-- Validation added -->
                    <lightning:input aura:id="formFieldToValidate" label="First Name" messageWhenValueMissing="Contact's First Name is Mandatory" required="true" value="{!v.contact.FirstName}" />
                    <!-- Validation added -->
                    <lightning:input aura:id="formFieldToValidate" label="Last Name" messageWhenValueMissing="Contacts's Last Name is Mandatory" required="true" value="{!v.contact.LastName}" />
                    <!-- Custom Validation added -->
                    <lightning:input aura:id="formFieldToValidate" label="Email" name="emailField" value="{!v.contact.Email}" />
                    <lightning:input label="Phone" value="{!v.contact.Phone}" />
                </div>
                <!-- Modal Footer ( consists of cancel and save buttons ) -->
                <footer class="slds-modal__footer">
                    <lightning:button onclick="{!c.closeModal}" variant="neutral">Cancel</lightning:button>
                    <lightning:button onclick="{!c.createContact}" variant="brand" >Save</lightning:button>
                </footer>
            </div>
        </section>
        <!-- Modal Backdrop -->
        <div aura:id="contactModalBackdrop" class="slds-backdrop"></div>
    </div>
</aura:component>
I have made changes in mainly the edit form and the new record form i.e. the modal which is used to create a new contact. The edit form is mainly the form with aura:id as recordEditForm. In the edit form, focus on the fields with <!-- Validation added --> comments, the first field is the Last name field, as the last name of a contact is required so I have set the required attribute to true and there is another attribute named messageWhenValueMissing i.e. this message will be displayed as a validation error when value of required attribute is missing. So, I have provided a message for the same as - Contact's Last Name is Mandatory. Another validation is for the phone field in which we added a pattern, when we created this form so we have to add that type of validation error message in the respective attribute. So, the attribute used here is messageWhenPatternMismatch and a friendly message is given that will be displayed when this attribute doesn't follow the pattern specified. One more thing to notice is that all the fields that are marked for validation has the same aura:id as fieldToValidate. <lightning:input> allows us to add validations in all fields at once, so I have given the same aura id to access all as an array. You'll see its usage when we move on to controller. The same procedure is applied to add validations in fields included in modal. In those fields, one field has <!-- Custom Validation added --> comment in which there is no particular message as we are going to use it to add custom validation. I have also added an aura:method attribute with name as validateContact and action as {!c.validateContact} which is the function that we have defined in controller. This function will be called from controller itself, that's why we need to specify it using aura:method tag to have it's definition in component so that it can be called using the component reference as component.validateContact(); | general syntax - component.<aura method name attribute>();

2. Lightning Controller

Moving on to the last part of our validation i.e. Lightning Controller, let's have a look at the code below before discussion.
({
    // Function called on initial page loading to get contact list from server
    getContactsList : function(component, event, helper) {
        // Helper function - fetchContacts called for interaction with server
        helper.fetchContacts(component, event, helper);
    },

    // Function used to create a new Contact
    newContact: function(component, event, helper) {
        // Global event force:createRecord is used
        var createContact = $A.get("e.force:createRecord");
        // Parameters like apiName and defaultValues are set
        createContact.setParams({
            "entityApiName": "Contact",
            "defaultFieldValues": {
                "AccountId": component.get("v.recordId")
            }
        });
        // Event fired and new contact dialog open
        createContact.fire();
    },

    // Function used to update the contacts
    editContacts: function(component, event, helper) {
        // Getting the button element
        var btn = event.getSource();
        // Getting the value in the name attribute
        var name = btn.get('v.name');
        // Getting the record view form and the record edit form elements
        var recordViewForm = component.find('recordViewForm');
        var recordEditForm = component.find('recordEditForm'); 
        // If button is edit
        if(name=='edit') {
            // Hiding the recordView Form and making the recordEdit form visible
            $A.util.addClass(recordViewForm,'formHide');
            $A.util.removeClass(recordEditForm,'formHide');
            // Changing the button name and label
            btn.set('v.name','save');
            btn.set('v.label','Save');
        }
        else if(name=='save') {
            // Getting the edit form fields to validate
            var contactFields = component.find("fieldToValidate");
            // Initialize the counter to zero - used to check validity of fields
            var blank=0;
            // If there are more than 1 fields
            if(contactFields.length!=undefined) {
                // Iterating all the fields
                var allValid = contactFields.reduce(function (validSoFar, inputCmp) {
                    // Show help message if single field is invalid
                    inputCmp.showHelpMessageIfInvalid();
                    // return whether all fields are valid or not
                    return validSoFar && inputCmp.get('v.validity').valid;
                }, true);
                // If all fields are not valid increment the counter
                if (!allValid) {
                    blank++;
                }
            } else {
                // If there is only one field, get that field and check for validity (true/false)
                var allValid = contactFields;
                // If field is not valid, increment the counter
                if (!allValid.get('v.validity').valid) {
                    blank++;
                }
            }
            // Call the helper method only when counter is 0
            if(blank==0) {
                // Calling saveContacts if the button is save
                helper.saveContacts(component, event, helper);                
            }
        }
    },
    
    // Function used to delete the contacts
    deleteContacts: function(component, event, helper) {
        // Calling removeContacts Helper Function
        helper.removeContacts(component, event, helper);
    },

    // Function used to open the contact modal
    openModal: function(component, event, helper) {
        var modal = component.find("contactModal");
        var modalBackdrop = component.find("contactModalBackdrop");
        $A.util.addClass(modal,"slds-fade-in-open");
        $A.util.addClass(modalBackdrop,"slds-backdrop_open");
    },

    // Function used to close the contact modal
    closeModal: function(component, event, helper) {
        var modal = component.find("contactModal");
        var modalBackdrop = component.find("contactModalBackdrop");
        $A.util.removeClass(modal,"slds-fade-in-open");
        $A.util.removeClass(modalBackdrop,"slds-backdrop_open");
    },

    // Function used to create new contact
    createContact: function(component, event, helper) {
        var isContactValid = component.validateContact(component, event, helper);
        if(isContactValid) {
           helper.insertContact(component, event, helper);
        }
    },

    // Function to validate new contact - Aura method used for the same
    validateContact: function(component, event, helper) {
        // Getting all fields and iterate them to check for validity
        var allValid = component.find('formFieldToValidate').reduce(function (validSoFar, inputCmp) {
            // Show help message if single field is invalid
            inputCmp.showHelpMessageIfInvalid();
            // Get the name of each field
            var name = inputCmp.get('v.name');
            // Check if name is emailField
            if(name=='emailField') {
                // Getting the value of that field
                var value = inputCmp.get('v.value');
                // If value is not equal to rahul@gmail.com, add custom validation
                if(value != 'rahul@gmail.com') {
                    // Focus on that field to make custom validation work
                    inputCmp.focus();
                    // Setting the custom validation
                    inputCmp.set('v.validity', {valid:false, badInput :true});
                }                
            }
            // Returning the final result of validations
            return validSoFar && inputCmp.get('v.validity').valid;
        }, true);
        // Returning Validate contact result in boolen
        return allValid;
    }

})
In the above code, I have made some changes in the editContacts and createContact function, and also added a new function named validateContact for which we used the aura:method tag in the component. Starting with the editContacts  function, earlier in this, in the save section we called helper.saveContacts() and performed all the server related tasks there. But now we have to validate the fields first. In save section, First of all, we get all the fields with aura id fieldToValidate and store it in variable contactFields. Now, it may be possible that component.find return a single element too if there is only one field on which the validation is applied. So, if the contactFields is an array (checked by length!=undefined as an array should have a length). We are applying the reduce function to contactFields which is a javascript method in which we iterate each element of array and here we refer it by inputCmp.

The reduce function takes 2 parameters:- first the function whose result we have to return and 2nd the initial value or initial result. So, initially we have assumed that all fields are valid so we have given true as the 2nd parameter and in the first parameter, the function will take two parameters, first the result till now and 2nd the current element and the return value of this function will further be passed to the same function in next iteration in the first parameter (result till now). We have 2 variables validSoFar and inputCmp. If you want more detailed explaination for the reduce function(), I am sharing a link here. Inside the function which is passed as first argument to reduce, first we called inputCmp.showHelpMessageIfInvalid(); this is a predefined method that will show our error message when we click on save button if the particular inputCmp is invalid and then we simply returned our validSoFar && inputCmp.get('v.validity').valid this means there are 2 possibilities, either our result from the previous iteration was false so validSoFar is false and the result will be false again. If all the fields till now are valid then we and the current result with the validity of current inputCmp therefore, if the inputCmp is not valid, the result of AND operation will be false and this false result is passed to the next iteration as the validSoFar parameter. We have a counter named blank whose value is incremented if all fields are not valid. Similarly if the component.find() doesn't return an array, we checked it's valid attribute i.e. if it returns false, then we further increment the blank counter ( you can check this by removing the fieldToValidate aura id from one of the two input fields as this will lead to only one field left with that aura id and the condition will be executed ). Finally, if the blank counter has a value 0, this means that all our fields are valid. Therefore, saveContacts() method of helper is called and the contacts are saved. Till now we have worked on applying validations to the edit form which looks like this:-

Custom Validation

Moving on to our createContact() function, we called the validContact() function that is also defined in the controller itself using component.validContact(component, event, helper). This is possible only because we have added aura:method tag in our lightning component. So, let's explore our validateContact function now and see what's there. It's much similar to out previous solution, in this also, we are calling component.find() on input fields with id formFieldToValidate. If you remember in the lightning component, I have given formFieldToValidate aura id to inputs that were in the modal which is mainly used to create a new Contact. Here I am not checking for array or single element as I know I have more than one fields with same aura:id so definitely, component.find() will return an array. I again called the showHelpMessageIfInvalid(). Now, I have to add custom validation on field with name emailField so I get the name of field using inputCmp.get("v.name") and if name equals emailField I am going to show an error if it's value is not equal to rahul@gmail.com this is just an example of custom validation you can add any other condition. So, I get the value of field using inputCmp.get("v.value") and if this value is not equal to rahul@gmail.com I focused on the inputCmp using inputCmp.focus() and set the validity attribute of inputCmp to {valid:false, badInput :true}. The validity attribute looks like this:-


This means that I am making the validity attribute of that field invalid and the reason is badInput as I am making that true and finally I am returning the AND of  validSoFar and current input fields validity and the default value is true just like before. But if you notice the contactList component, in the modal email field, we haven't given any attribute and it's value like :- messageWhenBadInput="" so the default message will be displayed i.e. Enter a valid value.So, in this way, we can add custom validations in our lightning component and if you are wondering about that inputCmp.focus(); line so it's necessary to focus the particular field to show the custom validation error message to appear. You can remove this line and give it a try, in that case, you have to manually focus it to show the error message. Actually, the lightning:input tag is still in beta version so there maybe any further advancements possible to make custom validations more easier. If you want to learn more about the various validations we can apply and the respective attributes for lightning:input, you can find them in the official doc here. Just scroll down to the error messages part while viewing the same. Also, if you came across a better approach, feel free to share it in comments section below. We have applied custom validations in the modal section and it looks like this:-


Tired of reading or just scrolled down..!! Don't worry, you can watch the video too.

If you liked this post then do follow, subscribe, comment your views or any feedback and share it with everyone in your circle so that they can also get benefit by this. Hope to see you next time too when we'll learn how to use lightning events hopefully as most of the people were demanding for a tutorial on that. For the whole code at one place, please refer to my github repository here. You can fork this repo and do your own changes. However please switch to validate branch to get the code specified here and not the future changes. Otherwise, directly go to the validate branch by clicking here.

Congratulations..!! You have completed all the 5 parts in Salesforce Lightning Basics Tutorial Series. Now before moving to the next step i.e. Salesforce Lightning Events Tutorial Series. Let's have a look at a small thank you gift - sObject Convertor that I have made for you for supporting SFDC Stop upto this level.

Happy Trailblazing..!!