Why do I need dynamic UI
Dynamic UI is useful in scenarios where the variation in UI are too large to be handled as field set or by building conditional logic in the code. For eg: A global client has presence in 100+ countries around the global. At the core the sales process has same fundamentals however each country have their own regional nuances such has different data capture requirements, different validations etc.
Solution: Dynamic UI generated at run time.
Recipe for generating dynamic UI
Why custom metadata?
There are two key benefits of using custom metadata type instead of a custom object or custom settings
Step 3: Create a visualforce page that will call dynamic component
Dynamic UI is useful in scenarios where the variation in UI are too large to be handled as field set or by building conditional logic in the code. For eg: A global client has presence in 100+ countries around the global. At the core the sales process has same fundamentals however each country have their own regional nuances such has different data capture requirements, different validations etc.
Solution: Dynamic UI generated at run time.
Recipe for generating dynamic UI
- Custom Metadata to store the field details that needs to be displayed
- DynamicUIHelper to build the Dynamic Components
- VF Page to call Apex:DynamicComponents
- Apex Controller to call DynamicUIHelper
Why custom metadata?
There are two key benefits of using custom metadata type instead of a custom object or custom settings
- The query for fetching information from custom metadata are not counted towards SOQL limits for the transaction.
- Apex test class can see values in custom metadata without using "SeeAllData" annotation.
For more details on custom metadata type please refer: Custom Settings vs Custom Metadata
- Country Applicable: Stores country name for which the fields should be displayed in the UI. You could replace this field with any other fields that defines your filter criteria.
- Help Text Reference: Allows you to have multiple help text for same field.
- Object Name: Stores API Name of custom object where the field resides
- Required?: If the field should be marked as required in the UI
- Screen Name: Stores name of the VF Page where the fields will be displayed
- Screen Sequence: The sequence in which the fields should be added:
- Group Sequence: Could be used to group fields in page sections in the UI
- Custom Style: Could be used to add a custom style sheet to the fields.
Step 2: Create an Apex class that will read the information stored in the "UI Setting" metadata type and generate UI Components
public class DynamicUIHelper {
Map<String,Schema.SObjectType> gd;
//Constructor to initialize variables
public DynamicUIHelper()
{
gd = Schema.getGlobalDescribe();
}
/*
* Method to generate dynamic UI
* Paramters
* ScreenName : Screen for which UI needs to be generated
* CountryName: Country for which UI needs to be generated
* ObjName : Object where data will be stored
* prefix: Reference of the Object to be used to bind fields with the object from Controller
*/
public Component.Apex.OutputPanel fetchUI(String screenName,String countryName, String objName, String prefix)
{
//Declare variable
//create an outer panel
Component.Apex.OutputPanel opPanel = new Component.Apex.OutputPanel();
Map<String,String> fieldAPILabelMap = new Map<String,String>();
List<UI_Settings__mdt> fieldInfoList = new List<UI_Settings__mdt>();
List<FieldSetWrapper> fsetList = new List<FieldSetWrapper>();
//schema defination for the target sObject
Schema.SObjectType sobjType = gd.get(objName);
Schema.DescribeSObjectResult describeResult = sobjType.getDescribe();
Map<String,Schema.SObjectField> fieldsMap = describeResult.fields.getMap();
//Iterate through the fieldMap and prepare fieldAPI and fieldLabel
for(String fieldName: fieldsMap.keySet())
{
fieldAPILabelMap.put(fieldName, fieldsMap.get(fieldName).getDescribe().getLabel());
}
//query information from UI Settings Metadata and create list of wrapper class
fieldInfoList = [Select Id,DeveloperName,Country_Applicable__c,Help_Text_Reference__c,
Object_Name__c,Required__c,Screen_Name__c, Screen_Sequence__c,Field_API_Name__c
from UI_Settings__mdt
where Screen_Name__c =: screenName AND Object_Name__c =: objName AND Country_Applicable__c =: countryName
order by Screen_Sequence__c];
for(UI_Settings__mdt uiRec: fieldInfoList)
{
String fieldLabel;
String fieldApi;
fieldLabel = fieldAPILabelMap.get(uiRec.Field_API_Name__c);
fieldApi = uiRec.Field_API_Name__c;
FieldSetWrapper fWrp = new FieldSetWrapper(fieldApi,fieldLabel,uiRec.Required__c,fieldApi);
fsetList.add(fWrp);
}
//add page block section
Component.Apex.PageBlockSection pbSec = new Component.Apex.PageBlockSection();
pbSec.title = 'Some Title';
pbSec.columns = 2;
//add the section to opPanel
opPanel.childComponents.add(pbSec);
for(FieldSetWrapper fw: fsetList)
{
//create input field
Component.Apex.InputField inpField = new Component.Apex.InputField();
//assign uique id to element
inpField.id = fw.fieldAPI;
inpField.label = fw.fieldLabel;
//assign value to the input field
inpField.expressions.value = '{!'+prefix+'.'+fw.fieldAPI+'}';
//create output label for the field
Component.Apex.OutputLabel outlbl = new Component.Apex.outputLabel();
outlbl.value = fw.fieldLabel;
//add label to the input field
inpField.childComponents.add(outlbl);
//add field to the page block section
pbSec.childComponents.add(inpField);
}
return opPanel;
}
//wrapper class
public class FieldSetWrapper
{
public String fieldapiname {get;set;}
public String fieldLabel {get;set;}
public Boolean required {get;set;}
public String fieldAPI {get;set;}
public FieldSetWrapper(String apiname, String flabel, Boolean req, String ssfieldAPI)
{
fieldapiname = apiname;
fieldLabel = flabel;
required = req;
fieldAPI = ssfieldAPI;
}
}
}
Step 3: Create a visualforce page that will call dynamic component
<apex:page controller="AccountVFController">
<apex:form >
<apex:pageBlock >
<!-- CALL DYNAMIC COMPONENT -->
<apex:dynamicComponent componentValue="{!opPanelAccount}"/>
</apex:pageBlock>
</apex:form>
</apex:page>
Step 4: Create apex controller that will call the helper class and pass the filter parameter countryName, Screen or UI name, SObject where data would be stored and instance of that SObject.
/*
* Controller for AccountVF
* Author: Prateek Sengar
*/
public class AccountVFController
{
public transient Component.Apex.OutputPanel opPanelAccount{get; set;}
public Account acc{get;set;}
//Constructor
public AccountVFController()
{
//call DynamicUIHelper to generate FetchUI
DynamicUIHelper DUIRef = new DynamicUIHelper();
//get screenName based on your condition
String screenName = 'Demo Screen';
//get countryName based on your condition
String countrName = 'United States of America';
//call the method to generate dynamic UI
opPanelAccount = DUIRef.fetchUI(screenName ,countrName ,'Account', 'acc');
}
}
No comments:
Post a Comment