0

I created a custom Related Record component for a specific sObject, but I'd like to make it dynamic so I can use the same component for two more sObjects.

Here's the code:

<aura:component implements="force:hasRecordId,flexipage:availableForRecordHome">
    <aura:attribute name="socialPostRecord" type="Object"/>
    <aura:attribute name="recordLoadError" type="String"/>
    
    <force:recordData aura:id="recordLoader"
    recordId="{!v.recordId}"
    fields="Persona.Parent.Name, Persona.Parent.Email, Persona.Parent.Phone"
    targetFields="{!v.socialPostRecord}"
    targetError="{!v.recordLoadError}"
    />
    
    <div> 
        <lightning:card iconName="standard:contact" title="Contatto" >
            <div class="slds-p-horizontal--small">
                <a onclick="{!c.handleClick}">
                <label class="slds-form-element__label" for="Nome e cognome">Nome e cognome</label>
                <p class="slds-truncate"><lightning:formattedText title="Nome e cognome" value="{!v.socialPostRecord.Persona.Parent.Name}" /></p>
                </a>                
                <label class="slds-form-element__label" for="Email">Email</label>
                <p class="slds-truncate"><lightning:formattedText title="Email" value="{!v.socialPostRecord.Persona.Parent.Email}" /></p>
                <label class="slds-form-element__label" for="Telefono">Telefono</label>
                <p class="slds-truncate"> <lightning:formattedText title="Telefono" value="{!v.socialPostRecord.Persona.Parent.Phone}" /></p>
            </div>
        </lightning:card>
    </div>
</aura:component>

The thing is, the fields on the other sObjects have different names, so the same component won't work.

Is there a simple solution to make this reusable for different sObjects? Would adding the other sObjects' fields in the force:recordData fields and then show them based on what object I am on?

1 Answer 1

0

You can make it dynamic without too much extra work. Here's the minimum changes you'd need to make:

<aura:component implements="force:hasRecordId,force:hasSObjectName,flexipage:availableForRecordHome">
    <aura:attribute name="record" type="Map" />
    <aura:attribute name="recordLoadError" type="String"/>

    <!-- these will be Design Attributes -->
    <!-- CSV (Comma Separated Values) list of field API names
    <aura:attribute name="fields" type="String" access="public" />
    <!-- CSV list of field labels (to avoid writing any Apex) -->
    <aura:attribute name="fieldLabels" type="String" access="public" />
    <!-- Icon name, e.g. standard:contact -->
    <aura:attribute name="recordIcon" type="String" access="public" />

    <!-- this is processed data -->
    <aura:attribute name="hasLoadedData" type="Boolean" default="{!false}" />
    <!-- csv list of fields from design attribute -->
    <aura:attribute name="fieldsList" type="List" />
    <!-- output data for header column (the "<a onclick>" column)-->
    <aura:attribute name="headerColumn" type="Map" default="{}" />
    <!-- output data for remaining columns (aura:iteration)-->
    <aura:attribute name="formattedFields" type="List" default="[]" />
    
    <!-- called when the component initially loads -->
    <aura:handler name="init" value="{!this}" action="{!c.init}" />

    <!-- recordUpdated is called when we have our data loaded -->
    <force:recordData aura:id="recordLoader"
    recordId="{!v.recordId}"
    fields="{!v.fieldsList}"
    recordUpdated="{!c.updateView}"
    targetFields="{!v.record}"
    targetError="{!v.recordLoadError}"
    />
    
    <div> 
        <lightning:card iconName="{!v.recordIcon}" title="{!v.sObjectName}" >
            <div class="slds-p-horizontal--small">
                <a onclick="{!c.handleClick}">
                <label class="slds-form-element__label" for="headerColumnValue">{!v.headerColumn.label}</label>
                <p class="slds-truncate"><lightning:formattedText title="{!v.headerColumn.label}" value="{!v.headerColumn.value}" /></p>
                </a>
                <aura:iteration items="{!v.formattedFields}" var="field">
                    <label class="slds-form-element__label" for="{!field.name}">{!field.label}</label>
                    <p class="slds-truncate"><lightning:formattedText title="{!field.label}" value="{!field.value}" /></p>
                </aura:iteration>
            </div>
        </lightning:card>
    </div>
</aura:component>

// Controller
({
    init: function(c, e, h) {
        // Split CSV string to proper array for force:recordData
        const fields = c.get("v.fields");
        c.set("v.fieldsList", fields.split(/, ?/));
    },
    // We now have new data
    updateView: function(c, e, h) {
        const record = c.get("v.record");
        // Extract first column info
        const [headerFieldName, ...otherFields] = c.get("v.fieldsList");
        const [headerFieldLabel, ...otherLabels] = c.get("v.fieldLabels").split(/, ?/);
        // Output is nested objects, so we need getFieldFromPath
        const headerFieldValue = h.getFieldFromPath(record, headerFieldName);
        const headerColumn = {
            label: headerFieldLabel, value: headerFieldValue
        };
        // Transform our data to a flattened list of objects
        const formattedFields = otherFields.map((v,i) => ({
            label: otherLabels[i], value: h.getFieldFromPath(record, v)
        }));
        c.set("v.hasLoadedData", true);
        c.set("v.headerColumn", headerColumn);
        c.set("v.formattedFields", formattedFields);
    }
})

// Helper 
({
    getFieldFromPath: function(record, sourceField) {
        const path = sourceField.split(/\./);
        let output = record;
        for(const field in path) {
            output = output[field];
        }
        return output;
    }
})

There is no error handling in this code. You will need to do some additional work to get this finished. This is only a bare-minimum fix to get you started with your dynamic component.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .