Let me share an overall architecture that I used to accomplish a very similar problem. The first thing I did was to create an apex class FieldDetail
to model a field describe with @AuraEnabled
get methods for all relevant information like label, data type, etc. Next, an inputField
component was created to consume that information and conditionally render a specific component using $A.createComponent()
depending on the data type. Note that we used both lightning
namespaced components as well as some components from the strike project. Once we had an input that could render itself for a FieldDetail
, it was simply a task of adding a top level controller that would retrieve a list of FieldDetail
objects and iterating over them to render a c:inputField
component for each field. In your case that controller may have a method signature similar to:
@auraEnabled
public static List<FieldDetail> getRequiredFieldDetails(String sObjectName)
You could then pass the sObjectName
parameter from either a design attribute or using one of the built in interfaces like force:hasSObjectName
and use object and field describes to build your list of FieldDetail
objects.
== Code Sample Update ==
The following class represents the details for a specific field and can be returned from an @AuraEnabled
method to be consumed in Lightning.
/**
* SObjectFieldDetail object provides information of an SObject Field for
* thge lightning context.
*/
public with sharing class SObjectFieldDetail {
private SObject record { get; set; }
private Schema.SObjectField field { get; set; }
/**
* Constructor
*/
public SObjectFieldDetail(SObject record, Schema.SObjectField field) {
this.record = record;
this.field = field;
}
@auraEnabled
/**
* @returns String value of the DisplayType of the field
*/
public String getType() {
Schema.DisplayType dataType = field.getDescribe().getType();
return String.valueOf(dataType);
}
@auraEnabled
/**
* @returns Label of the field
*/
public String getLabel() {
return field.getDescribe().getLabel();
}
@auraEnabled
/**
* @returns Returns true if the field is html formatted. (Rich Text)
* URL Fields return false
*/
public Boolean getIsHtmlFormatted() {
return field.getDescribe().isHtmlFormatted();
}
@auraEnabled
/**
* @returns True, if current user has read access.
*/
public Boolean getHasReadAccess() {
return field.getDescribe().isAccessible();
}
@auraEnabled
/**
* @returns True, if current user has write access.
*/
public Boolean getHasEditAccess() {
return field.getDescribe().isCreateable();
}
@auraEnabled
/**
* @returns Returns field name
*/
public String getFieldName() {
return field.getDescribe().getName();
}
@auraEnabled
/**
* @returns Returns local field name
*/
public String getFieldLocalName() {
return field.getDescribe().getLocalName();
}
@auraEnabled
/**
* @returns If the field type is picklist, returns List of the label of all picklist options.
* Else, returns empty list.
*/
public List<String> getAllPicklistOptions() {
List<String> picklistOptions = new List<String>();
if(getType() == 'PICKLIST'){
List<Schema.PicklistEntry> picklistValues = field.getDescribe().getPicklistValues();
for(Schema.PicklistEntry picklistEntry : picklistValues){
picklistOptions.add(picklistEntry.getLabel());
}
}
return picklistOptions;
}
@auraEnabled
/**
* @returns If the field type is picklist, returns List of the label of active picklist options.
* Else, returns empty list.
*/
public List<String> getPicklistOptions() {
List<String> picklistOptions = new List<String>();
if(getType() == 'PICKLIST'){
List<Schema.PicklistEntry> picklistValues = field.getDescribe().getPicklistValues();
for(Schema.PicklistEntry picklistEntry : picklistValues){
if(picklistEntry.isActive()){
picklistOptions.add(picklistEntry.getLabel());
}
}
}
return picklistOptions;
}
@auraEnabled
/**
* @returns If the field type is picklist, returns List of the label of active picklist options.
* Else, returns empty list.
*/
public String getDefaultPicklistOption() {
if(getType() == 'PICKLIST'){
return String.valueOf(field.getDescribe().getDefaultValue());
}
return null;
}
@auraEnabled
/**
* @returns Current value of the field
*/
public Object getCurrentValue() {
if(getHasReadAccess()){
return record.get(field);
}
else {
return null;
}
}
@auraEnabled
/**
* @returns String value of the DisplayType of the field
*/
public String getSObjectName() {
return record.getSObjectType().getDescribe().getName();
}
@auraEnabled
/**
* @returns String value of the DisplayType of the field
*/
public String getSObjectLocalName() {
return record.getSObjectType().getDescribe().getLocalName();
}
@auraEnabled
/**
* @returns Current max length of field
*/
public Integer getFieldLength() {
return field.getDescribe().getLength();
}
@auraEnabled
/**
* @returns Current max length of field
*/
public Integer getFieldPrecision() {
return field.getDescribe().getPrecision();
}
@auraEnabled
/**
* @returns Current max number of digits of field
*/
public Integer getFieldDigits() {
return field.getDescribe().getDigits();
}
@auraEnabled
/**
* @returns Current max number of digits of field right of decimal
*/
public Integer getFieldScale() {
return field.getDescribe().getScale();
}
@auraEnabled
/**
* @returns Current max number of digits of field right of decimal
*/
public Decimal getStep() {
Decimal step = 1;
for(Integer i = 0; i < getFieldScale(); i++){
step = step / 10;
}
return step;
}
@auraEnabled
/**
* @returns Current max number of digits of field right of decimal
*/
public Decimal getMax() {
Integer count = getFieldPrecision() - getFieldScale();
String str = '';
for(Integer i = 0; i < count; i++){
str = str + '9';
}
if(getFieldScale() > 0){
str = str + '.';
for(Integer i = 0; i < getFieldScale(); i++){
str = str + '9';
}
}
if(str.length() > 0){
return Decimal.valueOf(str);
}
else {
return 0;
}
}
You can then construct instances of this class by passing in a record (this could be a new record like new Contact()
and a list of fields. If you wanted all required fields, you use code similar to
List<Schema.SObjectField> allContactFields = Schema.Contact.sObjectType.getDescribe().fields.getMap().values();
List<Schema.SObjectField> requiredContactFields = new List<Schema.SObjectField>();
for(Schema.SObjectField field : allContactFields) {
if(field.getDescribe().isCreateable() && !field.getDescribe().isNillable() && !field.getDescribe().isDefaultedOnCreate()) {
requiredContactFields.add(field);
}
}