What if you want to create a child record from the parent record page in lightning? What is most feasible and quick solution here?
Of course Lightning Object Specific Quick Action, right?
Well, there is a small issue, what if you want to select the “Record Type” before creating the record? Yes, object-specific out of the box quick action does not support dynamic record type selection, however, you can select the default record type when creating the quick action.
So what is the solution here? 🤔
The solution is to create a Lightning Component which allows you to select the record type before creating the record. So let’s create our component which:
- Can be added as Quick Action
- Should allow us to select available “Record Types”
- Should allow us to create the child record
Scenario: We need a quick action on Account record detail page, which can create child Contact records using selected record type.
Your code should look like this
RecordTypeSelector.apxc
public class RecordTypeSelector{ /* * This function will fetch the RecordTypes of * provided object and will return a map of * recordTypeId and recordTypeNames * it excludes 'master' record type * */ public static Map<Id, String> recordtypemap; @AuraEnabled public static Map<Id, String> fetchRecordTypeValues(String objectName){ List<Schema.RecordTypeInfo> recordtypes = Schema.getGlobalDescribe().get(objectName).getDescribe().getRecordTypeInfos(); recordtypemap = new Map<Id, String>(); for(RecordTypeInfo rt : recordtypes){ if(rt.getName() != 'Master' && rt.getName().trim() != '') recordtypemap.put(rt.getRecordTypeId(), rt.getName()); } return recordtypemap; } }
CreateContactWithRecordType.cmp
<aura:component controller="RecordTypeSelector" implements="force:lightningQuickActionWithoutHeader,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId" access="global" > <aura:attribute name="lstOfRecordType" type="String[]" /> <aura:attribute name="mapOfRecordType" type="Map" /> <!-- Fetch all available record types after component construction but before rendering --> <aura:handler name="init" value="{!this}" action="{!c.fetchListOfRecordTypes}"/> <lightning:layout multipleRows="true" horizontalAlign="center"> <lightning:layoutItem flexibility="auto" padding="around-small" size="12" largeDeviceSize="12" mediumDeviceSize="12" smallDeviceSize="12"> <lightning:formattedText value="Select Contact Record Type" /> </lightning:layoutItem> <lightning:layoutItem flexibility="auto" padding="around-small" size="12" largeDeviceSize="12" mediumDeviceSize="12" smallDeviceSize="12"> <!-- select to hold all available record type names list --> <lightning:select aura:id="recordTypePickList" name="selectRecordType" label="Select a Record Type"> <option value="" text="Select Record Type"/> <aura:iteration items="{!v.lstOfRecordType}" var="item"> <option value="{!item}" text="{!item}"/> </aura:iteration> </lightning:select> </lightning:layoutItem> <lightning:layoutItem flexibility="auto" padding="around-small" size="3" largeDeviceSize="3" mediumDeviceSize="3" smallDeviceSize="6"> <lightning:button variant="brand" label="Next" onclick="{!c.createRecord}"/> </lightning:layoutItem> <lightning:layoutItem flexibility="auto" padding="around-small" size="3" largeDeviceSize="3" mediumDeviceSize="3" smallDeviceSize="6"> <lightning:button variant="neutral" label="Cancel" onclick="{!c.closeModal}" /> </lightning:layoutItem> </lightning:layout> </aura:component>
CreateContactWithRecordTypeController.js
({ /* * This method is being called from init event * to fetch all available recordTypes * */ fetchListOfRecordTypes: function(component, event, helper) { var action = component.get("c.fetchRecordTypeValues"); //pass the object name here for which you want //to fetch record types action.setParams({ "objectName" : "Contact" }); action.setCallback(this, function(response) { var mapOfRecordTypes = response.getReturnValue(); component.set("v.mapOfRecordType", mapOfRecordTypes); var recordTypeList = []; //Creating recordTypeList from retrieved Map for(var key in mapOfRecordTypes){ recordTypeList.push(mapOfRecordTypes[key]); } if(recordTypeList.length == 0){//Object does not have any record types //Close Quick Action Modal here helper.closeModal(); //Calling CreateRecord modal here without providing recordTypeId helper.showCreateRecordModal(component, "", "Contact"); } else{ component.set("v.lstOfRecordType", recordTypeList); } }); $A.enqueueAction(action); }, /* * This method will be called when "Next" button is clicked * It finds the recordTypeId from selected recordTypeName * and passes same value to helper to create a record * */ createRecord: function(component, event, helper, sObjectRecord) { var selectedRecordTypeName = component.find("recordTypePickList").get("v.value"); if(selectedRecordTypeName != ""){ var selectedRecordTypeMap = component.get("v.mapOfRecordType"); var selectedRecordTypeId; //finding selected recordTypeId from recordTypeName for(var key in selectedRecordTypeMap){ if(selectedRecordTypeName == selectedRecordTypeMap[key]){ selectedRecordTypeId = key;//match found, set value in selectedRecordTypeId variable break; } } //Close Quick Action Modal here helper.closeModal(); //Calling CreateRecord modal here without providing recordTypeId helper.showCreateRecordModal(component, selectedRecordTypeId, "Contact"); } else{ alert('You did not select any record type'); } }, /* * closing quickAction modal window * */ closeModal : function(component, event, helper){ helper.closeModal(); } })
CreateContactWithRecordTypeHelper.js
({ /* * This methid takes recordTypeId and entityTypeName parameters * and invoke standard force:createRecord event to create record * if recordTypeIs is blank, this will create record under master recordType * */ showCreateRecordModal : function(component, recordTypeId, entityApiName) { debugger; var createRecordEvent = $A.get("e.force:createRecord"); if(createRecordEvent){ //checking if the event is supported if(recordTypeId){//if recordTypeId is supplied, then set recordTypeId parameter createRecordEvent.setParams({ "entityApiName": entityApiName, "recordTypeId": recordTypeId, "defaultFieldValues": { "AccountId": component.get("v.recordId") } }); } else{//else create record under master recordType createRecordEvent.setParams({ "entityApiName": entityApiName, "defaultFieldValues": { "AccountId": component.get("v.recordId") } }); } createRecordEvent.fire(); } else{ alert('This event is not supported'); } }, /* * closing quickAction modal window * */ closeModal : function(){ var closeEvent = $A.get("e.force:closeQuickAction"); if(closeEvent){ closeEvent.fire(); } else{ alert('force:closeQuickAction event is not supported in this Ligthning Context'); } }, })
Create a Lightning Component Quick Action
Once you have developed your lightning component, you need to add this as a quick action on Account Object. Follow this gif to create a new quick action named “Create Contact” using CreateContactWithRecordType component:
Add your quick action to Account Page Layout
Now add your quick action “Create Contact” to Account Object page layout to display this action on the page. Follow this gif:
What we did
- We have created an Apex Controller RecordTypeSelector to fetch all available record type list.
- We have implemented force:lightningQuickActionWithoutHeader interface in our component to make it available for use as quick action.
- We have created lightning:select component to hold record type list.
- We have used force:createRecord standard event to create a new record.
- We have passed “recordTypeId” parameter to force:createRecord event to create a record with selected record type name.
- We have supplied “defaultFieldValues” parameter to pass AccountId to new Contact Record.
- Created new lightning component quick action named “Create Contact”.
- Added quick action to Account Page layout.
Output
The code should be self-explanatory as I have added comments everywhere. Please post a comment if you have any queries.
That’s it guys!! Your new lightning component is ready and available for use. 🤗
Hi Manish, it helped a lot. I have a trouble in one scenario, I hope you can help me. please send an email to ak144.sfdc@gmail.com, so that I can be in contact with you.
Hi Arav,
I am glad that it helped. Please do reach out to me at https://www.linkedin.com/in/manish-choudhary/
How to hide default popup of Quick Action.One Default Dialogue box is populated automatically when we are clicking on Quick Action.
Hey Keyur,
Which interface you are using:
1. force:lightningQuickActionWithoutHeader
2. force:lightningQuickAction
The first one allows a component to display in a panel without additional controls. The component should provide a complete user interface for the action.
The 2nd additional controls as well.
You can only use one of these at a time.
In your case, you should use force:lightningQuickActionWithoutHeader.
Hey Manish ,
I have a small question here . I don’t want to open the whole edit page while creating the record but rather a small layouts with only fields require to create a new record . So lets say I create a GLobal quick action with a layout and I need to call the layout of the global action from Lightning Component . Opening the whole page on mobile , its not very justified
There are 2 ways to do that:
1. Either use your own custom component to create a record and limit the number of fields there.
2. Or if you are using standard event (like in this example), you need to limit the field on page layout associated with the record type. The only problem with this solution is, it will limit the number of field even on the web browser (not only mobile browser)
Hi Manish,
I have a small issue here, you are pre populate the account name but, I want to populate other fields also can you please suggest me how to do that.
Yes Sandeep,
You can prepopulate any field of same object which you are creating. In my case, I was creating “Contact” record, so I can populate any contact field.
Hi Manish,
I have a small issue after creating an event from the opportunity, the Event is not shown on activity related to the Opportunity.
Would you please help me in this issue.
Hi Behzad,
Events are treated in a different way in Salesforce. Can you check in newly created event if WhatId matches to opportunity id.
Hi Manish,
yes, WhatId is matching to the Opportunity Id.
Thank you very much for your help.
Hi Manish,
As I am completely new with coding I need again your help,
I am going to write an Apex Class but I am getting an error I would appreciate if you take a look in the below.
@isTest
public class recordtypeSelectorTest {
static testmethod void testFetchRecordTypes() {
List values = recordtypeselector.fetchRecordTypeValues();
}
static testmethod void testgetRecordTypeId() {
String recordTypeLabel = ‘Consultant Termin’;
ID testId = recordtypeSelector.getRecTypeId(recordTypeLabel);
System.assert(testId != null);
}
}
Error: Compile Error: Method does not exist or incorrect signature: void fetchRecordTypeValues() from the type RecordTypeSelector at line 5 column 46
You need to pass object name to function “fetchRecordTypeValues”. Change your line 5 to something like below:
recordtypeselector.fetchRecordTypeValues(‘Account’);
-Replace ‘Account’ with your object name.
Hi,
Can we disable or hide the ‘Save and New’ button shown on the create record popup?’
That is the standard component and cannot be modified.
Works fine – thank you for the code and the detailed instructions. However: The RecordType selector ignores the profile settings for available record types. Only when saving the new record, the user gets an error message telling him that the record type id isn’t valid for the user.
How could I fix that?
Hi Ralf,
You Apex Code runs in system context hence it is giving all the record type even when the user does not have access to that record type. However, you can avoid this by using sample code below:
List recordTypes = new List ();
for(RecordTypeInfo info: Account.SObjectType.getDescribe().getRecordTypeInfos()) {
if(info.isAvailable()) {
recordTypes.add(new SelectOption(info.getRecordTypeId(), info.getName()));
}
}
// Include these next 3 lines to output the results during development and debugging
for( SelectOption selopt: recordTypes ) {
System.debug( selopt.getLabel() + ',' + selopt.getValue() );
}
HI Manish,
How can auto redirect recordtype based on parentb field.lets say i have parent object Lead having picklist field with value A ,B,C.
Lead_Age__c is a custom object which is lookup with Lead,and having 2 record type (New Value,Old Value)..
When I am creating child from parent there is option for record type select.But need to redirect directly recordtype page based on parent picklist value.No need to select any record type.If picklsit value A then at the time of child creation (when click on new button in child it auto direct New value Record type directly and like this.)
This can be done Mahes. While calling e.force.ceateRecord, just pass the recordTypeId you are getting from lead object and skip recordType selection page.
When we use event “e.force:createRecord” for the selected Object(Contact) can we select few fields rather default pagelayout?
You may have to override the “New Contact” page for contact object.