[SalesForce] How to use $A.createComponents() on lightning:recordEditForm with nested lightning:inputField

I've asked this question to change the objectApiName attribute of lightning:recordEditForm. Thanks to the great answer of @PranayJaiswal I found a workaround.

Now I soon will face the need of having to create recordEditForm components dynamically. The use case are very long lists of SObjects where I have to make rows editable.

I want to create the recordEditForm and the nested inputFields dynamically by $A.createComponents following a suggestion of @sfdcfox in the context of the original question but now intentionally like this:

makeEdit : function(cmp, evt, hlp) { 
    console.log('ParentId :: ', cmp.get("v.ParentId") ); 
    console.log('ParentType :: ', cmp.get("v.ParentType") ); 
    $A.createComponents([
            ["lightning:recordEditForm",{
                "recordId"          : cmp.get("v.ParentId"),
                "objectApiName"     : cmp.get("v.ParentType"),
            }],
            ["lightning:inputField",{
                "fieldName" : "Name"
            }]
        ]
        ,function(components, status, errorMessage){
            if (status === "SUCCESS") {
                var wrapper         = components[0];
                var inner           = components[1];
                wrapper.set("v.body", [inner]);
                cmp.set("v.body", [wrapper]);
            }
            else if (status === "INCOMPLETE") {
                console.log("No response from server or client is offline.")
                // Show offline error
            }
            else if (status === "ERROR") {
                console.log("Error: " + errorMessage);
                // Show error message
            }
        }
    );
},

Now I can invoke the controller code – but nothing – I repeat: n o t h i n g – gets rendered at all. What is my fault here? Note that the console.log gets executed and the output confirms that the attribute are holding good values.

Why this is not working?

See more code here.

Best Answer

I came up with a way to do this; you have to create the children first, and then the parent, similar to how the system would do it in mockup. Here's a demonstration:

<aura:application extends="force:slds">
    <aura:attribute name="recordEdit" type="Aura.Component[]" />
    <aura:handler name="init" value="{!this}" action="{!c.init}" />
    {!v.recordEdit}
</aura:application>

({
    init: function(component, event, helper) {
        // First, create children
        $A.createComponents([
            ["lightning:inputField", { fieldName: "Name"}],
            ["lightning:inputField", { fieldName: "Industry" }]
        ], (components, status, errors) => {
            // Then parent, specifying body of lightning:inputFields
            $A.createComponents(
            [["lightning:recordEditForm", { recordTypeId: "01250000000QNyF", objectApiName: "Account", body: components }]], 
                            (components, status, errors) => {
                                component.set("v.recordEdit", components);
                            });
        });
    }
})