@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.
Answer
Have you tried to extend force:inputField
component?
From what I’m seen on Aura Documentation, force:inputField
is abstract and extensible.
If you extend this component you can use renderers to change the output DOM and assign LDS classes.
I don’t know if this ok to do, I haven’t found anything around avoiding extending standard components.
Hope this works!
Attribution
Source : Link , Question Author : Jag , Answer Author : Ratan Paul