Create Record By Lightning Data Service

Create Record By Lightning Data Service

In this section, we will create a Contact Record from Account using Lightning Data Service(LDS) in Lightning Experience.

Step 1: Create a component bundle named “createContactByLDS”.

createContactByLDS.cmp | to create Contact record from Account by LDS

<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId,lightning:availableForFlowScreens">

    <aura:attribute name="account" type="Object"/>
    <aura:attribute name="loadedAccountFields" type="Object"/>
    <aura:attribute name="accountError" type="String"/>

    <aura:attribute name="newContact" type="Object"/>
    <aura:attribute name="newContactFields" type="Object"/>
    <aura:attribute name="newContactError" type="String"/>
    

    <force:recordData aura:id="accountRecordLoaderId"
        recordId="{!v.recordId}"
        fields="Name"
        targetRecord="{!v.account}"
        targetFields="{!v.loadedAccountFields}"
        targetError="{!v.accountError}"
    />

    <force:recordData aura:id="contactRecordCreatorId"
        layoutType="FULL"
        targetRecord="{!v.newContact}"
        targetFields="{!v.newContactFields}"
        targetError="{!v.newContactError}" 
    /> 

    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>

    <div class="slds-page-header" role="banner">
        <p class="slds-text-heading_label">{!v.loadedAccountFields.Name}</p>
        <h1 class="slds-page-header__title slds-m-right_small
            slds-truncate slds-align-left">Create New Contact</h1>
    </div>
    <lightning:card >
        <aura:if isTrue="{!not(empty(v.accountError))}">
            <div class="recordError">
                <ui:message title="Error" severity="error" closable="true">
                    {!v.accountError}
                </ui:message>
            </div>
        </aura:if>
        <aura:if isTrue="{!not(empty(v.newContactError))}">
            <div class="recordError">
                <ui:message title="Error" severity="error" closable="true">
                    {!v.newContactError}
                </ui:message>
            </div>
        </aura:if>

        <lightning:layout multiplerows="true" verticalalign="center">
            <lightning:layoutItem padding="around-small" size="12">
                <lightning:input aura:id="contactField" 
                                 name="firstName" 
                                 label="First Name"
                                 value="{!v.newContactFields.FirstName}"/>
              
                <lightning:input aura:id="contactField" 
                                 name="lastname" 
                                 label="Last Name"
                                 value="{!v.newContactFields.LastName}" 
                                 required="true"/>
                        
                <!--<lightning:input aura:id="contactField" 
                                 type="phone" 
                                 name="phone" 
                                 label="Phone Number"
                                 pattern="^(1?(-?\d{3})-?)?(\d{3})(-?\d{4})$"
                                 messageWhenPatternMismatch="The phone number must contain 7, 10, or 11 digits. Hyphens are optional."
                                 value="{!v.newContactFields.Phone}" 
                                 required="true"/>-->
                
                <lightning:input aura:id="contactField" 
                                 type="email" 
                                 name="email" 
                                 label="Email"
                                 value="{!v.newContactFields.Email}" />
                
                <div class="slds-float_right">
                    <lightning:button label="Reset" onclick="{!c.doReset}" class="slds-m-top_medium" />
                    <lightning:button label="Save" onclick="{!c.saveContact}"
                                      variant="brand" class="slds-m-top_medium"/>
                </div>                
           </lightning:layoutItem>
       </lightning:layout>    
    </lightning:card>
</aura:component>

createContactByLDSController.js | to call the standard Save operation by LDS

({
    doInit: function(component, event, helper) {
        helper.openNewContact(component);
    },

    saveContact: function(component, event, helper) {
        if(helper.validateContactForm(component)) {
            component.set("v.newContactFields.AccountId", component.get("v.recordId"));
            component.find("contactRecordCreatorId").saveRecord(function(saveResult) {
                if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") {

                    var resultsToast = $A.get("e.force:showToast");
                    resultsToast.setParams({
                        "title": "Success! ",
                        "message": "The new contact was created.",
                        "type":"success"
                    });

                    $A.get("e.force:closeQuickAction").fire();
                    resultsToast.fire();

                    $A.get("e.force:refreshView").fire();
                    helper.openNewContact(component);
                }
                else if (saveResult.state === "INCOMPLETE") {
                    console.log("User is offline, device doesn't support drafts.");
                }
                else if (saveResult.state === "ERROR") {
                    console.log('Problem saving contact, error: ' +
                                 JSON.stringify(saveResult.error));
                }
                else {
                    console.log('Unknown problem, state: ' + saveResult.state +
                                ', error: ' + JSON.stringify(saveResult.error));
                }
            });
        }
    },

    doReset: function(component, event, helper) {
        //$A.get("e.force:closeQuickAction").fire();
        helper.openNewContact(component);
    },
})

createContactByLDSHelper.js | to reset and validate the form of the Contact

({
    
    openNewContact: function(component){
        component.find("contactRecordCreatorId").getNewRecord(
            "Contact", // objectApiName
            null, // recordTypeId
            false, // skip cache?
            $A.getCallback(function() {
                var rec = component.get("v.newContact");
                var error = component.get("v.newContactError");
                if(error || (rec === null)) {
                    console.log("Error initializing record template: " + error);
                }
                else {
                    console.log("Record template initialized: " + rec.sobjectType);
                }
            })
        );
    },


    validateContactForm: function(component) {
        var validContact = true;
        var allValid = component.find('contactField').reduce(function (validFields, inputCmp) {
            inputCmp.showHelpMessageIfInvalid();
            return validFields && inputCmp.get('v.validity').valid;
        }, true);

        if (allValid) {
            var account = component.get("v.account");
            if($A.util.isEmpty(account)) {
                validContact = false;
                console.log("Quick action context doesn't have a valid account.");
            }
        	return(validContact);
            
        }  
	}
       
})

We have used openNewContact form to instantiate the Contact record means every time it will open the blank Contact template at the time of loading contact or at the time of doReset function is called from controller.js file.

We are validating the contact by using standard javascript reduce function. The standard showHelpMessageIfInvalid() throws the error message for the lightning:input where value is missing or pattern is not matched.

You can get the details in the reference link: https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/data_service_example.htm#data_service_example

Step 2: That’s it. Now just add this component into the Lightning record Page of an Account.

Results

Notes

1.

<force:recordData aura:id="accountRecordLoaderId"
        recordId="{!v.recordId}"
        fields="Name"
        targetRecord="{!v.account}"
        targetFields="{!v.loadedAccountFields}"
        targetError="{!v.accountError}"
    />

This is responsible to collect account name with respect to record Id.

2.

<force:recordData aura:id="contactRecordCreatorId"
        layoutType="FULL"
        targetRecord="{!v.newContact}"
        targetFields="{!v.newContactFields}"
        targetError="{!v.newContactError}" 
    /> 

This is responsible to create contact record. Please notice that, we have used layoutType instead of using fields. So, at the time of definition of Contact fields in the form, we can use any field resides on the Contact Object.

3. In createContactByLDSController.js file, we have set the Account Id of Contact just like component.set(“v.newContactFields.AccountId”, component.get(“v.recordId”)).

4. In createContactByLDSHelper.js file, we need to declare the instantiation of the Contact Record in the “openNewContact” function at Client Side for Lightning Data Service.

In the same file, we have used “validateContactForm” function to validate the Contact form.

5,885 total views, 3 views today

Load Record by Lightning Data Service

Loading record by Lightning Data Service

In Lightning Experience, we will load the Account record with some attributes from Contact by Lightning Data Service.

Step 1: Need to create a Lightning Component named “loadAccount“.

loadAccount.cmp | It will show the respective Account Details from the Contact record page.

<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId">

    <aura:attribute name="record" type="Object"/>
    <aura:attribute name="loadedRecordFields" type="Object"/>
    <aura:attribute name="recordError" type="String"/>

    <!-- Lightning Data Service -->
    <force:recordData aura:id="accountLoaderId"
				      recordId="{!v.recordId}"
				      fields="Name, Account.Name, Account.BillingCity, Account.BillingState"
				      targetFields="{!v.loadedRecordFields}"
				      targetError="{!v.recordError}"/>    
    
    <!-- Account Details Section -->
    <lightning:card iconName="standard:contact" title="{!v.loadedRecordFields.Name}" >
    	<div class="slds-p-horizontal--small">
        	<p class="slds-text-heading--small">
        		<div class="demo-only" style="padding: 0.5rem; background: rgb(22, 50, 92);">
  					<div class="slds-text-color_inverse">Account Details</div>
				</div><br/>
                <b>Name:</b> <lightning:formattedText title="Account Name" value="{!v.loadedRecordFields.Account.Name}" />
            </p>
            <p class="slds-text-heading--small">
                <b>BillingCity:</b> <lightning:formattedText title="Billing City" value="{!v.loadedRecordFields.Account.BillingCity}" />
            </p>
            <p class="slds-text-heading--small">
                <b>BillingState:</b> <lightning:formattedText title="Billing State" value="{!v.loadedRecordFields.Account.BillingState}" />
            </p>
        </div>
    </lightning:card>
 
 	<!-- Errors, if any -->
	<aura:if isTrue="{!not(empty(v.recordError))}">
        <div class="recordError">
            {!v.recordError}</div>
    </aura:if>
</aura:component>

Step 2: Please open any Contact record in Lightning Experience & click on “Edit Page” by Settings(Gear Icon at the top-right corner) and drag the “loadAccount” component to the right side of the Contact Lightning Record Page. After this, please save and activate the contact page.

Result
loaded account

You can see the red color highlighted portion of the Contact page and it will show the Account details from Contact: Mr. John Bond.

Notes

If you will use layoutType=”FULL” into “force:recordData“, you can only refer to the Name field of Account(Account.Name) from Contact, you can not refer other Account fields from Contact. That’s why, we have mentioned all the respective Account fields (Account.Name, Account.BillingCity, Account.BillingState) and Contact field(Name) both to query in the “fields” attribute. So, we have used “fields” instead of using “layoutType”.

3,364 total views, 3 views today

Lightning Data Service

What is Lightning Data Service(LDS)?
-Lightning Data Service is the data layer for Lightning. We can load, create, edit or delete a particular record by LDS without calling Server/Apex Class. You can compare Standard Visualforce Controller to Lightning Data Service.

PROS

1. LDS supports sharing rules and field level security.
2. Record loaded by LDS is cached and shared across all components.
3. Minimize XMLHttpRequests.
4. After record changes, notification process is available. You can compare with publish-subscriber model.
5. It is offline supported.

CONS

1. LDS is applicable to operate on a particular or single record at once. LDS is not supported for multiple records at once.
2. LDS is only applicable in Lightning Experience. It is not supported in Lightning Components calling from Visualforce page or Lightning Out. If this Visualforce Page is added into Lightning Experience or in Salesforce Mobile app, then LDS is supported.

Syntax


<force:recordData aura:id="accountInfoId" 
                  recordId="{!v.recordId}" 
                  mode="EDIT" layoutType="FULL" 
                  fields="Id, Name, Phone" 
                  targetRecord="{!v.record}" 
                  targetFields="{!v.simpleRecord}" 
                  targetError="{!v.errors}" 
                  recordUpdated="{!c.updateRecord}" />

A. force:recordData tag is to define Lightning Data Service.
B. force:recordData has some parameters to fulfill the Lightning Data Service. We will discuss one by one.

1. recordId: It defines the Record Id for which LDS will run.
2. mode: It can be “EDIT” or “VIEW“. It will tell the mode of operation.
3. layoutType: It will specify the Layout such as “FULL” or “COMPACT“.
4. fields: LDS will query for these fields internally.
5. fields or layoutType is required to query data by LDS.
6. targetRecord: It is populated with the loaded record.
7. targetFields: It is populated with the simplified view of the loaded record.
8. targetError: It is responsible to show the errors, if errors are occurred during operation.
9. recordUpdated: It is responsible to do certain operation if anything changes to the loaded record. Remember, for only this operation, we are calling method in javascript”{!c.updateRecord}”.

In the next articles, we will see how to load, create, edit or delete record using Lightning Data Service.

4,451 total views, 6 views today

Convert a List from a Map in Lightning Component

Convert a List from a Map in Lightning Component

In many projects, we have seen that we need to iterate a Map in Lightning component to satisfy the business requirement. But, it’s not possible in straightforward to iterate the Map at Component level. We have a solution for this. We can create a List from Map. We can create a List with Key and Value identifiers from a Map and then iterate the List and compare the Key and Value, if applicable.

Step 1: Need to create a Selector Class to return all the Contact records in a Map.

ContactSelector.apxc |  to return the Map of Contact records

public with sharing class ContactSelector {
	public static Map<Id,Contact> selectRecordsMap(){		
		return new Map<Id, Contact>([SELECT Id, Name, AccountId FROM Contact]);
	}
}

Step 2: To call the Selector Class(ContactSelector) to get the Map of Contact records.

SimpleMaptoListController.apxc |  to call the Selector Class “ContactSelector

public with sharing class SimpleMaptoListController {
	
	@AuraEnabled
	public static Map<Id,Contact> getContacts(){
		return ContactSelector.selectRecordsMap();
	}
}

Step 3: Create a Component Bundle named “simpleMaptoList”.

simpleMaptoList.cmp | to iterate the List converted from a Map returned from Server Side

<aura:component implements="flexipage:availableForAllPageTypes" controller="SimpleMaptoListController">
	<aura:attribute name="selectedContact" type="String"/>
	<aura:attribute name="contactList" type="List"/>
	
	<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>

	<lightning:card title="">
		<aura:set attribute="title">
			<lightning:icon iconName="utility:connected_apps" size="small"/>
			<span style="font-size: 2rem;" >Map to List</span>
		</aura:set>
		<lightning:layout multiplerows="true" verticalalign="center">
			<lightning:layoutItem padding="around-small" size="6">				
				<lightning:select name="Select a Contact" label="Select a Contact" aura:id="contactSelect" value="{!v.selectedContact}">
			        <aura:iteration items="{!v.contactList}" var="con">
                                    <option text="{!con.value}" value="{!con.key}"/>
			         </aura:iteration>
				</lightning:select> 
			</lightning:layoutItem>
		</lightning:layout>
	</lightning:card>
</aura:component>

simpleMaptoListController.js |  to call the helper function

({
	doInit : function(component, event, helper) {
		helper.performShowingContacts(component, event);
 	}
})

simpleMaptoListHelper.js | to convert a List from a Map returned from Server Side and to set the List variable in the Component

({
	performShowingContacts : function(component, event) {
		var action = component.get("c.getContacts");
		//action.setStorable();
		this.setupPerformShowingContactsAction(component, action);
		$A.enqueueAction(action);
	},

	setupPerformShowingContactsAction : function(component, action) {

		action.setCallback(this, function(response){
        	this.handlePerformShowingContactsResultsCallBack(component, response);
        });	
	},

	handlePerformShowingContactsResultsCallBack : function(component, response) {

		var responseState = response.getState();
		var responseError = response.getError();
		var responseValue = response.getReturnValue();

		var contacts = [];
		
		switch(responseState){

			default: break;
			case 'NEW': break;
			case 'RUNNING': break;

			case 'SUCCESS':

				if(responseValue != null){
					for(var key in responseValue){
						contacts.push({
							key: key,
							value: responseValue[key].Name
						});
					}
				}
				component.set("v.contactList", contacts);
				break;
					

			case 'INCOMPLETE': break;
			case 'ERROR': 
				console.log('Response Error-->'+JSON.stringify(responseError));
				break;

		}
	}
})

Steps to Remember

1. Create Apex Class to return the Map to Lightning Component.
2. Declare the List attribute in .cmp file.
3. In helper.js file, declare an array (in this assignment, we have declared an array named “contacts[]”) in which we will store the Map with Key-Value Pair.
4. Then, need to push the Key – Value pair into this array by looping the responseValue(Map) from Server Side just like

for(var key in responseValue){
 contacts.push({
 key: key,
 value: responseValue[key].Name
 });
}

5. Need to set the List attribute of component with this array which we have created in helper.js file.
6. At last, you have to iterate the List attribute to show the result in your component just like

<aura:iteration items="{!v.contactList}" var="con">
  <option text="{!con.value}" value="{!con.key}"/>
</aura:iteration>

8,672 total views, 5 views today

How to use Map in Lightning Component?

Map: This is an collection of Key-Value pair items. A Map can’t contain duplicate keys.

How to use Map in Lightning Component?

A. How can we define and access the Map in Lightning Component?
B. How can we define and access the Map in Lightning Component through Server?

A. How can we define and access the Map in Lightning Component?

Step 1: Create a Lightning Component Bundle named “simpleMap”.

simpleMap.cmp | showing the values from a map

<aura:component implements="flexipage:availableForAllPageTypes">

	<aura:attribute name="capitalMap" type="Map" default="{key1:'value1', key2:'value2'}"/>
	
	<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
			
	<span style="font-size: 1rem;">Capital</span>

	The capital of India: {!v.capitalMap.India}
	The capital of Nepal: {!v.capitalMap.Nepal}
	
					
</aura:component>

simpleMapController.js | define the map at controller.js file

({
	doInit : function(component, event, helper) {
		var capitalMap = component.get("v.capitalMap");

		//capitalMap["KEY"] = "VALUE";
		capitalMap["India"] = "New Delhi";
		capitalMap["Nepal"] = "KathMandu";
		
		component.set("v.capitalMap",capitalMap);
        console.log("The Capital of India: "+component.get("v.capitalMap")["India"]);		
	}
})

B. How can we define and access the Map in Lightning Component through Server?

Step 1: Need to write Apex Class where we will define the Map at Class level.

SimpleMapController.apxc | returns the map from server side

public with sharing class SimpleMapController {
	
	@AuraEnabled
	public static Map<String, String> getCapitals(){

		Map<String, String> capitalsMap = new Map<String, String>();
		capitalsMap.put('India', 'New Delhi');
		capitalsMap.put('Nepal', 'KathMandu');

		return capitalsMap;
		
	}
}

Step 2: Create a Lightning Component Bundle named “simpleMap”.

simpleMap.cmp | showing the values from a map

<aura:component implements="flexipage:availableForAllPageTypes" controller="SimpleMapController">

	<aura:attribute name="capitalsMap" type="Map"/>
	
	<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>

	<span style="font-size: 1rem;">Capital</span>

	The capital of India: {!v.capitalsMap.India}
	The capital of Nepal: {!v.capitalsMap.Nepal}
					
</aura:component>

simpleMapController.js | to call the helper function

({
	doInit : function(component, event, helper) {
		helper.performShowingCapitals(component, event);
 	}
})

simpleMapHelper.js | to set the map attribute of the component to the map returned from server side

({
	performShowingCapitals : function(component, event) {
		var action = component.get("c.getCapitals");
		this.setupPerformShowingCapitalsAction(component, action);
		$A.enqueueAction(action);
	},

	setupPerformShowingCapitalsAction : function(component, action) {

		action.setCallback(this, function(response){
        	this.handlePerformShowingCapitalsResultsCallBack(component, response);
        });	
	},

	handlePerformShowingCapitalsResultsCallBack : function(component, response) {

		var responseState = response.getState();
		var responseError = response.getError();
		var responseValue = response.getReturnValue();

		switch(responseState){

			default: break;
			case 'NEW': break;
			case 'RUNNING': break;

			case 'SUCCESS':

				if(responseValue != null)			
					component.set("v.capitalsMap", responseValue);
				break;
					

			case 'INCOMPLETE': break;
			case 'ERROR': 
				console.log('Response Error-->'+JSON.stringify(responseError));
				break;

		}
	}
})

Steps to remember

1. Declare the attribute of Map type in Component Level.
2. Need to set the Map sent by Apex Class or standalone in your javascript file to Map attribute in your Lightning Component by javascript file.
3. Need to print out the value of the Map in Component file in this way: {!v.mapAttribute.key}
4. Need to print out the value of the Map in javascript file in this way: component.get(“v.mapAttribute”)[“key”]

6,057 total views, 1 views today

How to use List in Lightning Component?

List: This is an ordered collection of items. A List can contain duplicate values. We can directly iterate List in Lightning Component.

How to use List in Lightning Component?

Step 1:  Need to write a Selector Apex Class which will return all the Contact Records from your organization.

ContactSelector.apxc | return all the Contact Records

/* @name: ContactSelector
   @description: return all the Contact Records*/

public with sharing class ContactSelector {
	public static List<Contact> selectRecords(){
	
        List<Contact> contactList = [SELECT Id, Name, AccountId FROM Contact];
	    
		if(contactList <> NULL && contactList.size()>0)
            return contactList;
        else
            return NULL;
	}
}

Step 2: Need to write Controller Class which will call the Selector class as mentioned above.

SimpleListController.apxc | to call the Selector class and get all the Contact records

/* @name: SimpleListController
   @description: to call the Selector class and get all the Contact records*/

public with sharing class SimpleListController {
	
	@AuraEnabled
	public static List<Contact> getContacts(){
		return ContactSelector.selectRecords();
	}
} 

Step 3: Please create a Lightning Component bundle named “simpleList”.

simpleList.cmp | to show all the contacts as picklist value

<!-- @name: simpleList @description: to show all the contacts as picklist value -->
<aura:component implements="flexipage:availableForAllPageTypes" controller="SimpleListController">
	
	<aura:attribute name="selectedContact" type="String"/>
	<aura:attribute name="contactList" type="List"/>
	
	<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
	
	<lightning:card title="Showing List">
		<lightning:select name="Select a Contact" label="Select a Contact" aura:id="contactSelect" value="{!v.selectedContact}">
			<aura:iteration items="{!v.contactList}" var="con">
                               <option text="{!con.Name}" value="{!con.Id}"/>
			</aura:iteration>
		</lightning:select> 
	</lightning:card>	
					
</aura:component>

simpleListController.js | to call the helper function

/*controller.js*/
({
	doInit : function(component, event, helper) {
		helper.performShowingContacts(component, event);
	}
})

simpleListHelper.js | to set the Component List to Contact List returned from Server Side

 | to call the method("getContacts") of the apex class("SimpleListController") to get all the Contacts
/*helper.js*/
({
	performShowingContacts : function(component, event) {
		var action = component.get("c.getContacts");
		//action.setStorable();
		this.setupPerformShowingContactsAction(component, action);
		$A.enqueueAction(action);
	},

	setupPerformShowingContactsAction : function(component, action) {

		action.setCallback(this, function(response){
        	this.handlePerformShowingContactsResultsCallBack(component, response);
        });	
	},

	handlePerformShowingContactsResultsCallBack : function(component, response) {

		var responseState = response.getState();
		var responseError = response.getError();
		var responseValue = response.getReturnValue();

		switch(responseState){

			default: break;
			case 'NEW': break;
			case 'RUNNING': break;

			case 'SUCCESS':

				if(responseValue != null)
				component.set("v.contactList", responseValue);
				break;

			case 'INCOMPLETE': break;
			case 'ERROR': 
				console.log('Response Error--&gt;'+JSON.stringify(responseError));
				break;

		}
	}
})

component.set(“v.contactList”, responseValue): You can see at Line No. 33 from helper.js file that we have set the contactList (attribute of List type in the component) to responseValue which is the List of Contacts returned by Apex Class.

So, you can iterate this List in your Lightning Component just like

<aura:iteration items="{!v.contactList}" var="con">
   <option text="{!con.Name}" value="{!con.Id}"/>
</aura:iteration>

Steps to remember

1. Declare the attribute of List type in Component Level.
2. Apex Class will be responsible to send the List of Values.
3. Helper.js file will set that Component List attribute to the responseValue which is the List returned by Apex Class.
4. Now, You can use this List in your Lightning Component.

8,255 total views, 2 views today

Call Lightning Component from Flow

Call Lightning Component from Flow

In this section, we will call a Lightning Component from a Flow. Same Assignment: Create a Contact by Lightning Component calling from a Flow. To do this assignment, we will use Lightning Data Service.

Step 1: Create a component bundle named “createContactByLDS”.

createContactByLDS.cmp | to create contact using Lightning Data Service. To refer this component to flow, you must implement “lightning:availableForFlowScreens” at the component level.

<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId,lightning:availableForFlowScreens">

    <aura:attribute name="account" type="Object"/>
    <aura:attribute name="loadedAccountFields" type="Object"/>
    <aura:attribute name="accountError" type="String"/>

    <aura:attribute name="newContact" type="Object"/>
    <aura:attribute name="newContactFields" type="Object"/>
    <aura:attribute name="newContactError" type="String"/>
    

    <force:recordData aura:id="accountRecordLoaderId"
        recordId="{!v.recordId}"
        fields="Name"
        targetRecord="{!v.account}"
        targetFields="{!v.loadedAccountFields}"
        targetError="{!v.accountError}"
    />

    <force:recordData aura:id="contactRecordCreatorId"
        layoutType="FULL"
        targetRecord="{!v.newContact}"
        targetFields="{!v.newContactFields}"
        targetError="{!v.newContactError}" 
        /> 

    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>

    <div class="slds-page-header" role="banner">
        <p class="slds-text-heading_label">{!v.loadedAccountFields.Name}</p>
        <h1 class="slds-page-header__title slds-m-right_small
            slds-truncate slds-align-left">Create New Contact</h1>
    </div>
    <lightning:card >
        <aura:if isTrue="{!not(empty(v.accountError))}">
            <div class="recordError">
                <ui:message title="Error" severity="error" closable="true">
                    {!v.accountError}
                </ui:message>
            </div>
        </aura:if>
        <aura:if isTrue="{!not(empty(v.newContactError))}">
            <div class="recordError">
                <ui:message title="Error" severity="error" closable="true">
                    {!v.newContactError}
                </ui:message>
            </div>
        </aura:if>

        <lightning:layout multiplerows="true" verticalalign="center">
            <lightning:layoutItem padding="around-small" size="12">
                <lightning:input aura:id="contactField" 
                                 name="firstName" 
                                 label="First Name"
                                 value="{!v.newContactFields.FirstName}"/>
              
                <lightning:input aura:id="contactField" 
                                 name="lastname" 
                                 label="Last Name"
                                 value="{!v.newContactFields.LastName}" 
                                 required="true"/>
                        
                <!--<lightning:input aura:id="contactField" 
                                 type="phone" 
                                 name="phone" 
                                 label="Phone Number"
                                 pattern="^(1?(-?\d{3})-?)?(\d{3})(-?\d{4})$"
                                 messageWhenPatternMismatch="The phone number must contain 7, 10, or 11 digits. Hyphens are optional."
                                 value="{!v.newContactFields.Phone}" 
                                 required="true"/>-->
                
                <lightning:input aura:id="contactField" 
                                 type="email" 
                                 name="email" 
                                 label="Email"
                                 value="{!v.newContactFields.Email}" />
                
                <div class="slds-float_right">
                    <lightning:button label="Reset" onclick="{!c.doReset}" class="slds-m-top_medium" />
                    <lightning:button label="Save" onclick="{!c.saveContact}"
                                      variant="brand" class="slds-m-top_medium"/>
                </div>                
           </lightning:layoutItem>
       </lightning:layout>    
    </lightning:card>
</aura:component>

createContactByLDSController.js | to save and reset the contact record

({
    doInit: function(component, event, helper) {
        helper.openNewContact(component);
    },

    saveContact: function(component, event, helper) {
        if(helper.validateContactForm(component)) {
            component.set("v.newContactFields.AccountId", component.get("v.recordId"));
            component.find("contactRecordCreatorId").saveRecord(function(saveResult) {
                if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") {

                    var resultsToast = $A.get("e.force:showToast");
                    resultsToast.setParams({
                        "title": "Success! ",
                        "message": "The new contact was created.",
                        "type":"success"
                    });

                    $A.get("e.force:closeQuickAction").fire();
                    resultsToast.fire();

                    $A.get("e.force:refreshView").fire();
                    helper.openNewContact(component);
                }
                else if (saveResult.state === "INCOMPLETE") {
                    console.log("User is offline, device doesn't support drafts.");
                }
                else if (saveResult.state === "ERROR") {
                    console.log('Problem saving contact, error: ' +
                                 JSON.stringify(saveResult.error));
                }
                else {
                    console.log('Unknown problem, state: ' + saveResult.state +
                                ', error: ' + JSON.stringify(saveResult.error));
                }
            });
        }
    },

    doReset: function(component, event, helper) {
        //$A.get("e.force:closeQuickAction").fire();
        helper.openNewContact(component);
    },
})

createContactByLDSHelper.js | to create a blank form and validation for the contact record

({
    
    openNewContact: function(component){
        component.find("contactRecordCreatorId").getNewRecord(
            "Contact", // objectApiName
            null, // recordTypeId
            false, // skip cache?
            $A.getCallback(function() {
                var rec = component.get("v.newContact");
                var error = component.get("v.newContactError");
                if(error || (rec === null)) {
                    console.log("Error initializing record template: " + error);
                }
                else {
                    console.log("Record template initialized: " + rec.sobjectType);
                }
            })
        );
    },


    validateContactForm: function(component) {
        var validContact = true;
        var allValid = component.find('contactField').reduce(function (validFields, inputCmp) {
            inputCmp.showHelpMessageIfInvalid();
            return validFields && inputCmp.get('v.validity').valid;
        }, true);

        if (allValid) {
            var account = component.get("v.account");
            if($A.util.isEmpty(account)) {
                validContact = false;
                console.log("Quick action context doesn't have a valid account.");
            }
        	return(validContact);
            
        }  
	}
       
})

createContactByLDS.design | to define an input attribute for this component

<design:component >
	<design:attribute name="recordId" label="Current Record Id"/>
</design:component>

Step 2: Create a flow where you will refer this Lightning Component. Just drag the Screen element in the Cloud Flow Designer and Select Lightning Component from “Add a Field” tab and set the input attribute named “recordId” of the Lightning Component. Save the flow named “Create Contact by Lightning Component” and activate it.

Step 3: Now, need to add the Flow in Lightning Record Page of Account. So, just open any account record and click “Edit Page” from Settings on the page and drag the “flow” into the record page. Now, select the flow name in the Lightning Record Page and select “Pass record ID into this variable” to send the record Id from Flow to Lightning Component.

Results

Steps to Remember

1. To refer any Lightning Component into the Flow, you must implement “lightning:availableForFlowScreens” at the component level.
2. If any attributes need to send to Lightning component from Flow, you have to define the design of Lightning Component just like

<design:component >
	<design:attribute name="recordId" label="Current Record Id"/>
</design:component>

3. When you will set the Lightning Component, you must set the input attribute of the Lightning Component.
4. When you will add the Flow in Lightning Record Page, do not forget to select “Pass record ID into this variable”, if needs to send record Id to Lightning Component via Flow.

3,360 total views, 4 views today

Call Flow from Lightning Component

Call Flow from Lightning Component

In this section, we will call a Flow from a Lightning Component. Same Assignment: Create a Contact by Flow calling from Lightning Component.

Step 1: Create a flow from Cloud Flow Designer. Already, we have created the flow in the last session. If you have missed out, Please click on the link to open the last session: Contact Creation Flow.

Step 2: Create a Lightning Component bundle named “createContactfromFlow“.

createContactfromFlow.cmp | calling a Flow from Lightning Component

<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId">	
    
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    
    <lightning:card >
    	<lightning:flow aura:id="createContactFlowId" onstatuschange="{!c.handleStatusChange}"/>
    </lightning:card>
</aura:component>

createContactfromFlowController.js | to start flow with input parameters

({
	doInit : function(component, event, helper) {
		var createContactFlowId = component.find("createContactFlowId");
        var inputVariables = [
            {
                name:"accountId",
                type:"String",
                value:component.get("v.recordId")
            }
        ];
        
        createContactFlowId.startFlow("Contact_Creation_Flow", inputVariables);
	},

    handleStatusChange : function(component, event, helper) {
        if(event.getParam("status") === "FINISHED") {
         /*var outputVariables = event.getParam("outputVariables");
          var outputVar;
          for(var i = 0; i < outputVariables.length; i++) {
             outputVar = outputVariables[i];
             if(outputVar.name === "contactId") {
                var urlEvent = $A.get("e.force:navigateToSObject");
                urlEvent.setParams({
                   "recordId": outputVar.value,
                   "isredirect": "true"
                });
                urlEvent.fire();
             }
          }*/
          $A.get('e.force:refreshView').fire();

       }
    }
})

Clarification

doInit: Initialize and starting the flow by aura:id. Now, we have the Input variable/attribute named “accountId” in the Flow. So, we need to send the current Account record Id to this flow input variable. Please check the syntax createContactFlowId.startFlow(“Contact_Creation_Flow”, inputVariables); “Contact_Creation_Flowis the API Name of the flow.

handleStatusChange: Salesforce has provided the functionality on flow called “onstatuschange” on lightning:flow. When the Status of flow has been changed, at that point of time respective function will be invoked.Here, the function’s name is “handleStatusChange”. We are doing refresh the related list of the current Account, when Status of the flow has been changed to “FINISHED“. You can redirect to the created record’s detail page. This code is commented out. You can check.

Step 3: Please place this Lightning Component in the Lightning Record Page of the Account record.

6,106 total views, 5 views today

Flow distribution for Lightning Record Page

Flow distribution for Lightning Record Page

In this section, we will learn how to refer flow in Lightning Record Page. We will create a contact record from an account by flow placing in account record page in Lightning Experience.

Basic Understanding on Contact Creation Flow by Cloud Flow Designer


 

Step 1: Please open Cloud Flow Designer from Set up screen(“search with ‘Flows’ keyword in the search box of left panel” ).

Step 2: Please create a Flow with all the necessary information. Please mark the respective element as Starter by green signal. Here, Record Lookup is our starting element of the flow.

Step 3: After creation, please activate the flow. Flow has the versioning system. You can create multiple versions for a flow, but only one version can be active at a time. Please find the screenshot of the active flow named “Contact Creation”. 

Record Lookup:  It looks us the current account record with respect to account record Id and returns the Account Name.
Contact Inputs Screen: It is the layout of the fields which are applicable for contact creation.
Record Create: It allows to run the DML statement means you can insert the Contact record by using this element.
Error Handling Screen: We can customize the error handling by Flow Fault Message.
Thank You Screen: It will display Thank You message after creation of Contact.

Step 4: Need to place this flow in Lightning Record Page of account. So, Please edit the Lightning Record Page and drag the flow into the respective section of this record page.

Step 5: We have created an input variable named “accountId” in the flow to take the current Account Record Id. Now, we have to pass the Account Record Id to “accountId” variable mentioned in the flow. So, after dragging the flow in the Lightning Record Page, Please check this checkbox “Pass Record ID into this variable”.

Remember, when you will drag this flow in the Lightning Record Page, you will not see the flow immediately because Flow doesn’t run in a canvas. After saving the Lightning Record Page with Flow, you can see the flow on the Account Record.

 

2,773 total views, 3 views today

How to use global value providers?

Global Value Providers: Salesforce has provided some global value providers to be used in Lightning Component expressions. So, you don’t need to write your own methods to take the Browser Information, Custom Labels etc..

Global Value ProviderFeatureSyntax
$LabelYou can access custom labels using this global value provider in your Lightning Component Bundle.in component/app(.cmp/.app) file
{!$Label.c.labelName}

in controller/helper.js/ any js file
$A.get("$Label.c.labelName")

if your organization has a namespace, please replace "c" with the namespace just like
{!$Label.namespace.labelName}  -- optional, you can refer "c" or "namespace" in cmp files.
$A.get("$Label.namespace.labelName") -- required to replace the namespace in JS files.
$Browser It provides the hardware and operating system of the browser accessing the application.in component/app(.cmp/.app) file

{!$Browser.isTablet}
{!$Browser.isPhone}
{!$Browser.isAndroid}
{!$Browser.isIOS}
{!$Browser.isWindowsPhone}
{!$Browser.isIPad}
{!$Browser.formFactor} => returns DESKTOP/PHONE/TABLET as enum value

in controller/helper.js/any js file

$A.get("$Browser.isIOS");
$ResourceIt is used to reference images, script files, style sheets and other files fro Static Resource$Resource is not downloaded until Lightning Component framework is loaded on the client side. To make sure, all files are loaded used rerender function.
in component/app(.cmp/.app) for taking image files
< !-- Standalone Image Files -- >
< img src="{!$Resource.imageName}" />
< img src="{!$Resource.namespace__imageName}" />

< !-- Archived Image Files -- >
< img src="{!$Resource.archivedImageFile + '/images/image1.jpg'}" />
< img src="{!$Resource.namespace__archivedImageFile + '/images/image1.jpg'}" />

in component/app(.cmp/.app) for taking Styles and Scripts files
scripts="{!$Resource.archivedScriptFile + '/samplescript.js'}"
afterScriptsLoaded="{!c.scriptsLoaded}" />

in controller/helper.js/any js file
$A.get('$Resource.archivedImageFile ') + '/images/image1.jpg'

Multiple files loaded into component at a same time. Need to use 'join' statement
scripts="{!join(' ,' , $Resource.archivedStyleFile + '/style1.js',
$Resource.archivedStyleFile + '/style2.js')}"

Manage Package Consideration
Static Resource Files are not automatically added into the package if it is referenced in JS files. You need to include the Static Resource Files manually into the package component list prior to upload.
$LocaleIt returns current user's locale information.in component/app(.cmp/.app) file
{!$Locale.language}

in controller/helper.js/any js file
$A.get("$Locale.language");

Some Important Locale Attributes

country                           returns ISO 3166 Code                                     "US", "GB"
currency                         returns Symbol                                                    "$"
currencyCode              returns ISO 4217 Code                                      "USD"
language                        returns language Code                                     "en"
timeZone                       returns timezone Id                                            "America/Los_Angeles"
dateFormat                   returns dateformat                                             "MMM d, yyyy"
timeFormat                   returns timeformat                                             "h:mm:ss a"

9,483 total views, 15 views today