[SalesForce] How Do I Work With Field Type Describe Information in Lightning Components

Good evening everyone,

I currently have a requirement where I need to create form fields dynamically from the Case object and render the same field types as on the Case object. I am trying to create functionality like the <apex:inputField> VisualForce tag provides. I have tried the force:inputField component but have not had any success getting that to work. I have seen several forum posts that have mentioned that component doesn't seem to be working correctly, at least not for desktop applications. Therefore, I am trying to find another way to dynamically render field types to a form and then dynamically bind the form field values back to the Case object to create the record in Salesforce on form submission.

My form component markup is below:

<aura:component controller="SelfServiceActionFormStep1Controller">
    <!-- Attributes -->
    <aura:attribute name="userMessage" type="Aura.Component[]"/>
    <aura:attribute name="actionWrapper" type="Object"/>
    <aura:attribute name="fieldset" type="String[]"/>
    <aura:attribute name="case" type="Case"
                    default="{'sobjectType': 'Case',
                             'Type_of_Leave__c': 'Personal',
                             'Total_Time_Off_Unit__c': 'Days',
                             'Origin': 'Self-Service',
                             'Type': 'New Time Off Request',
                             'Start_Date__c': ''
                             }"/>

    <!-- Registered Events -->
    <aura:registerEvent name="SelfServiceTimeOffNextStep" type="c:SelfServiceTimeOffNextStep"/>

    <!-- Event Handlers -->
    <aura:handler value="{!this}" name="init" action="{!c.doInit}"/>

    <div class="container-fluid">
        <div class="row" id="timeOffFormMsgDiv">
            <div class="col-md-6 col-md-offset-3 tc">
                {!v.userMessage}
            </div>
        </div>
        <div class="row mts">
            <div class="col-md-12>">
                <form class="form-horizontal">
                    <aura:iteration items="{!v.actionWrapper.describedFieldListStep1}" var="field">
                        <aura:if isTrue="{!field.type == 'date' ? 'true' : 'false'}">
                            <div class="form-group">
                                <div class="col-sm-5 col-sm-offset-1">
                                    <c:SelfServiceDateCmp aura:id="dateCmp" fieldLabel="{!field.label}" fieldName="{!field.name}" case="{!v.case}"/>
                                </div>
                            </div>
                        </aura:if>
                        <aura:if isTrue="{!field.type == 'double' ? 'true' : 'false'}">
                            <div class="form-group">
                                <div class="col-sm-5 col-sm-offset-1">
                                    <c:SelfServiceInputTextCmp aura:id="inputCmp" fieldLabel="{!field.label}" fieldName="{!field.name}" case="{!v.case}"/>
                                </div>
                            </div>
                        </aura:if>
                        <aura:if isTrue="{!field.type == 'picklist' ? 'true' : 'false'}">
                            <div class="form-group">
                                <div class="col-sm-5 col-sm-offset-1">
                                    <c:SelfServicePicklistTextCmp aura:id="picklistCmp" fieldLabel="{!field.label}" fieldName="{!field.name}" case="{!v.case}" picklistValues="{!field.picklistValues}"/>
                                </div>
                            </div>
                        </aura:if>
                    </aura:iteration> 
                    <div class="form-group">        
                        <div class="col-sm-offset-9 col-sm-3">
                            <button aura:id="step1NextBtn" type="button" class="btn btn-primary btn-custom prl pll" onclick="{!c.validateStep1}">Next</button>
                        </div>
                    </div>
                </form>
            </div>
        </div>                                              
    </div>
<ltng:require scripts="/resource/CommunityResources/js/jquery.min.js, /resource/CommunityResources/js/bootstrap.min.js" afterScriptsLoaded="{!c.OnScriptsLoaded}"/>
</aura:component>

The describedFieldListStep1 attribute you see referenced in the wrapper class I am returning contains the DescribeFieldResult information for all the fields I need to render to the form. I have each form field created as a separate component that I am rendering based on the field type. For example, the <c:SelfServiceDateCmp/> markup is below. You can see where I tried {!v.case.fieldName} to try and dynamically bind the API field name to the Case object, but that didn't work:

<aura:component >
    <!-- Attributes -->
    <aura:attribute name="case" type="Case"/>
    <aura:attribute name="fieldLabel" type="String" />
    <aura:attribute name="fieldName" type="String" />

    <aura:handler value="{!this}" name="init" action="{!c.doInit}"/>

    <div class="container-fluid">
        <div class="row">
            <label class="control-label" for="inputCmp">{!v.fieldLabel}</label>
            <ui:inputDate aura:id="inputDate" class="form-control" value="{!v.case.v.fieldName}" displayDatePicker="true"/>                                                                
        </div>
    </div>                                    
</aura:component>

This part is working fine as far as rendering the correct field types to the page.

The problem I am running into is how to bind the value attribute of the form field components to the Case standard object attribute outlined below that I have declared in this component and then am passing to the child components to update the appropriate fields.

<aura:attribute name="case" type="Case"
                    default="{'sobjectType': 'Case',
                             'Type_of_Leave__c': 'Personal',
                             'Total_Time_Off_Unit__c': 'Days',
                             'Origin': 'Self-Service',
                             'Type': 'New Time Off Request',
                             'Start_Date__c': ''
                             }"/>

I'm not able to simply specify {!v.case.Reason}, for example, because I'm not sure what field may be coming in and which Case field it should map to. I might have 3 different input fields that are created on the form, but I will only have the one <ui:inputText> component with the one value attribute.

I was thinking I might have to go to the client-side controller to get the values of each field individually and somehow build the case object on the Submit click event, but I'm not sure how that would work in Lightning.

Would anyone be able to provide some insight on this one?

Thanks!

Best Answer

You'll need to do this in javascript.

I'm a bit unsure when you want to do the component creation, I'm guessing at init, so in your c.init function, you'll have

var fieldName = cmp.get("v.fieldName");
$A.createComponent("ui:inputDate", { "value": cmp.getReference("v.case." + fieldName) }, function callback(newCmp) {  cmp.set("v.body", newCmp); });

You can see using cmp.getReference() is what creates the link you would normally get by using {!v.case.Reason} in the cmp file.

Related Topic