[SalesForce] Dynamically Building Nested HTML in Lightning Component

I'm currently trying to dynamically build nested HTML components using $A.createComponents, but it doesn't seem to be working (I'm receiving an error message: An internal server error has occured).

The output I'm trying to achieve is similar to (repeated for each field):

<td>
    <div class="slds-truncate" title="myDynamicTitle>My Dynamic Body Content</div>
</td>

My helper method is as follows:

populateRow : function(component) {
    var record = component.get("v.record");
    console.log('record = ' + JSON.stringify(record));
    var fields = component.get("v.fields");

    for (var idx in fields) {
        var field = fields[idx];
        var value = '';
        if(field.includes('.')) {
            value = record[field.substring(0, field.indexOf('.'))].Name
        } else {
            value = record[field];
        }
        $A.createComponents([
                ["aura:HTML", {
                    "tag": "td",
                    "HTMLAttributes": {
                        "id": "tdId"
                    }
                }],
                ["aura:HTML", {
                    "tag": "div",
                    "body": value,
                    "HTMLAttributes": {
                        "id": "dynamicDiv",
                        "title": value,
                        "class": "slds-truncate"
                    }
                }]
            ],
            function(components, status, errorMessage){
                if (status === "SUCCESS") {
                    var td = components[0];
                    var div = components[1];
                    td.set("v.body", div);

                    var container = cmp.find("container");
                    if (container.isValid()) {
                        var body = container.get("v.body");
                        body.push(td);
                        container.set("v.body", body);
                    }
                }
                else if (status === "INCOMPLETE") {
                    console.log("No response from server or client is offline.")
                    // Show offline error
                }
                else if (status === "ERROR") {
                    console.log("Error: " + JSON.stringify(errorMessage));
                    // Show error message
                }
            }
        );
    }
}

And my component (the init function calls the helper.populateRow function):

<aura:component description="DynamicListElement">
    <aura:attribute name="record" type="sObject" required="true"/>
    <aura:attribute name="fields" type="String[]" required="true"/>

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

    <aura:registerEvent name="dynamicListElementSelected" type="c:DynamicListElementSelected"/>

    {!v.body}
</aura:component>

Best Answer

It appears as if the issue is related to the $A.createComponents being in a for loop. I readjusted my code to the following to fix this issue:

populateRow: function (component) {
    var record = component.get("v.record");
    var fields = component.get("v.fields");

    // Array of components to create
    var newComponents = [];

    for (var idx in fields) {
        var field = fields[idx];
        var value = "";
        if (field.includes(".")) {
            value = record[field.substring(0, field.indexOf("."))].Name
        } else {
            value = record[field];
        }

        newComponents.push(["aura:html", {
            "tag": "td"
        }]);

        newComponents.push(["aura:html", {
            "tag": "div",
            "body": value,
            "HTMLAttributes": {
                "title": value,
                "class": "slds-truncate"
            }
        }]);
    }

    $A.createComponents(newComponents,
        function (components, status, errorMessage) {
            if (status === "SUCCESS") {
                var pageBody = component.get("v.body");
                for (var i = 0; i < components.length; i += 2) {
                    var td = components[i];
                    var div = components[i + 1];
                    var tdBody = td.get("v.body");
                    tdBody.push(div);
                    td.set("v.body", tdBody)
                    pageBody.push(td);
                }
                component.set("v.body", pageBody);
            }
            else // Report any error
            {
                this.displayToast("Error", "Failed to create list components.");
            }
        }
    );
}
Related Topic