@SkipSauls wrote an amazing article on how to use FieldSets in Lightning Components. Thank you!
But it seems like, using this approach, we can only use OOTB aura components (ui:textbox, ui:button) . But these components are not compatible with Lightning Design System.
Hence i started creating generic custom components (c:customComponent) and used it when creating dynamic components using $A.createComponent(....).
But creating generic components (with LDS Support) which supports all different types of metadata seems to consume enormous time.
Is there a better way to approach it?
I am trying to see if there is a better way such as usage of "force:inputfield" inside $A.createComponent(...) so that Salesforce Platform can determine and render components using respective metadata automatically.
Have anyone tried this approach ? It doesn't seem to work for me.
Here is my first Try (This works, but too painful and time consuming to build all generic components).
PageLayoutManager.cmp
<aura:component access="GLOBAL" controller="PageLayoutManagerApexController"
implements="force:appHostable,flexipage:availableForAllPageTypes,force:hasRecordId">
<!-- Public Page Attributes -->
<aura:attribute name="fieldSetName" type="String" access="global"/>
<aura:attribute name="lazyLoad" type="Boolean" default="true" access="global"/>
<aura:attribute name="totalColumns" type="Integer" access="global"/>
<aura:attribute name="dataTransportMode" type="String" access="global"
description="Enables to pass-in values by data-wrapper [OR]
by providing fieldSet Name.
Accepted Values: (FieldSet [OR] DataWrapper)" />
<!-- Private Page Attributes -->
<aura:attribute name="fieldWrapperList" type="object" access="private" />
<!-- Context Aware Attributes -->
<aura:attribute name="recordId" type="String" default="a0Dg000000636rzEAA" />
<aura:attribute name="sObjectName" type="String" default="KYCOnboard__c"/>
<!-- Page Handlers -->
<aura:handler name="init" value="{!this}" action="{!c.onInit}" />
<!-- Future Functionality -->
<aura:attribute name="dataWrapper" type="Object" />
<!-- Dynamic UI Markup -->
<div class="slds">
<div class="slds-col">
<aura:iteration items="{!v.body}" var="bodyElement">
<div class="slds-form-element">
{!bodyElement}
</div>
</aura:iteration>
</div>
</div>
</aura:component>
PageLayoutManagerController.js
({
onInit : function(component, event, helper) {
console.log("PageLayoutManager -- onInit() -- ENTRY");
helper.getFieldSetMetadata(component, helper);
console.log("PageLayoutManager -- onInit() -- EXIT");
}
})
PageLayoutManagerHelper.js
({
getFieldSetMetadata : function(component, helper) {
console.log("PageLayoutManager -- helper.getFieldSetMetadata() -- ENTRY");
var SObjectName = component.get("v.sObjectName");
var FieldSetName = component.get("v.fieldSetName");
var RecordId = component.get("v.recordId");
//Getting Apex Method Instance
var action = component.get("c.getApexFieldSetMetadata");
if(SObjectName && FieldSetName){
action.setParams({
sObjectName : SObjectName,
fieldSetName : FieldSetName,
recordId : RecordId
});
$A.enqueueAction(action);
console.log('getFieldSetMetadata() - Request Initalized to Apex Controller ');
var self = this;
//Handle Response back from Apex Controller.
action.setCallback(self, function(response){
var callbackState = response.getState();
var fieldWrapperList = response.getReturnValue();
if(callbackState === "SUCCESS"){
console.log('getFieldSetMetadata() - Response...');
console.table(response.getReturnValue());
component.set("v.fieldWrapperList", fieldWrapperList);
helper.constructDynamicComponents(component, helper, fieldWrapperList);
}else if(callbackState === "ERROR"){
console.log('Something went wrong!');
}
});
}
console.log("PageLayoutManager -- helper.getFieldSetMetadata() -- EXIT");
},
constructDynamicComponents : function(component, helper, fieldWrapperList){
console.log("PageLayoutManager -- helper.constructDynamicComponents() -- ENTRY");
var componentTypeConfigMap = JSON.parse(JSON.stringify(this.componentTypeConfigObj));
var componentAttributesConfigMap;
for(var i = 0; i < fieldWrapperList.length; i++){
componentAttributesConfigMap = {};
//Configure Attributes
componentAttributesConfigMap["aura:id"] = component.getGlobalId();
componentAttributesConfigMap["label"] = fieldWrapperList[i].label;
componentAttributesConfigMap["access"] = "Global";
//Component Specific Attributes
if(fieldWrapperList[i].type == "STRING"){
componentAttributesConfigMap["class"] = "slds-input";
}else if(fieldWrapperList[i].type == "DATETIME"){
componentAttributesConfigMap["class"] = "slds-input";
componentAttributesConfigMap["displayDatePicker"] = "true";
}else if(fieldWrapperList[i].type == "REFERENCE"){
componentAttributesConfigMap["class"] = "slds-input";
}
//Create Dynamic Components
//Syntax: createComponent(String type, Object attributes, function callback)
$A.createComponent(
componentTypeConfigMap[fieldWrapperList[i].type],
componentAttributesConfigMap,
function(dynamicCmp){
if(component.isValid()){
var body = component.get("v.body");
body.push(dynamicCmp);
console.log(body);
component.set("v.body", body);
}
}
);
}
console.log("PageLayoutManager -- helper.constructDynamicComponents() -- EXIT");
},
componentTypeConfigObj: {
"DATETIME" : "c:GenericInputDate",
"REFERENCE" : "ui:inputText",
"STRING" : "c:GenericInputTextBox"
}
})
PageLayoutManagerApexController.aspx
public class PageLayoutManagerApexController {
/* PUBLIC METHODS */
@AuraEnabled
public static List<fieldSetWrapper> getApexFieldSetMetadata(String sObjectName, String fieldSetName, String recordId){
Map<String, Schema.FieldSet> fieldSetMap = new Map<String, Schema.FieldSet>();
/*
To Do: Since the component is within <aura:iteration>, getAllFieldSets() would be called
several items. Hence move the "fieldSetMap" to Platform Cache -- Jag
*/
if(!String.isBlank(sObjectName)){
fieldSetMap = getAllFieldSets(sObjectName);
}
//Exit quickly, if no fieldSet is found associated to sObject
if(fieldSetMap.size() > 0){
return getFieldMetadata(fieldSetMap, fieldSetName);
}else{
return null;
}
}
/* PRIVATE METHODS */
private static Map<String, Schema.FieldSet> getAllFieldSets(String sObjectName){
//Get sObject in Schema.SObjectType format
Schema.SObjectType sObjectType = Schema.getGlobalDescribe().get(sObjectName);
//Then, get sObjectResult which has all the metadata info. about sObject.
Schema.DescribeSObjectResult describesObjectRes = sObjectType.getDescribe();
//sObject Result Schema has info about fieldSets. Store it in a Map.
Map<String, Schema.FieldSet> fieldSetMap = describesObjectRes.fieldSets.getMap();
System.debug('FieldSet Map: ' + fieldSetMap);
return fieldSetMap;
}
private static List<fieldSetWrapper> getFieldMetadata(Map<String, Schema.FieldSet> fieldSetMap, String fieldSetName){
List<Schema.FieldSetMember> fieldSetMemberList = new List<Schema.FieldSetMember>();
if(!String.isBlank(fieldSetName)){
Schema.FieldSet fieldSet = fieldSetMap.get(fieldSetName);
if(!String.isBlank(String.valueOf(fieldSet))){
fieldSetMemberList = fieldSet.getFields();
}
System.debug('FieldSet Members : ' + fieldSetMemberList);
if(fieldSetMemberList.size() > 0){
List<fieldSetWrapper> fswList = new List<fieldSetWrapper>();
for(Schema.FieldSetMember fsm: fieldSetMemberList){
fieldSetWrapper fsw = new fieldSetWrapper(fsm);
fswList.add(fsw);
}
if(fswList.size() > 0){
return fswList;
}else{
return null;
}
}else{
return null;
}
}else{
return null;
}
}
/*
Wrapper Class
*/
public class fieldSetWrapper{
@AuraEnabled
public Boolean DBRequired {get; set;}
@AuraEnabled
public String fieldPath {get; set;}
@AuraEnabled
public String label {get; set;}
@AuraEnabled
public Boolean required {get; set;}
@AuraEnabled
public String type {get; set;}
public fieldSetWrapper(Schema.FieldSetMember fieldSetMember){
this.DBRequired = fieldSetMember.getDbRequired();
this.fieldPath = fieldSetMember.getFieldPath();
this.label = fieldSetMember.getLabel();
this.required = fieldSetMember.getRequired();
this.type = String.ValueOf(fieldSetMember.getType());
}
}
/* FieldSetMember Structure Reference */
/*
FieldSet Members: (
Schema.FieldSetMember[
getDbRequired = false;
getFieldPath = KYC_Risk_Officer__c;
getLabel = KYC Risk Officer;
getRequired = false;
getType = REFERENCE;
],
Schema.FieldSetMember[
getDbRequired = false;
getFieldPath = Name;
getLabel = KYCOnboard Name;
getRequired = false;
getType = STRING;
]
)
*/
}
Console Log Output
Here is the piece of code i am trying to make it work
for(var i = 0; i < fieldWrapperList.fswList.length; i++){
$A.createComponent(
"force:inputField",
{
"aura:id" : component.getGlobalId(),
"label" : fieldWrapperList.fswList[i].label,
"value" : fieldWrapperList.sObjectInstance.KYC_Risk_Officer__c
},
function(dynamicCmp){
if(component.isValid()){
var body = component.get("v.body");
body.push(dynamicCmp);
console.log(body);
component.set("v.body", body);
}
}
);
}
Any help would be appreciated! Thank you.