I need to create an edit component for an SObject from which I do not know the objectApiName at design time. I only know the Id of the SObject. objectApiName could be any valid SObject-name.
Now I want to use lightning:inputField
This needs to be wrapped by lightning:recordEditForm
In case I hardcode it to "Order", provide a vaild Order Id and let the controller load the order and assign it to the Parent-attribute, this works flawlessly:
<aura:attribute name="recordId" type="String" default="" />
<aura:attribute name="Parent" type="SObject" default="{}" />
<aura:attribute name="ParentType" type="String" default="" />
<b>{!v.ParentType}({!v.recordId})</b>
<br/>
<lightning:recordEditForm recordId="{!v.recordId}" objectApiName="Order">
<lightning:messages />
<lightning:inputField fieldName="Name" />
<lightning:button class="slds-m-top_small" variant="brand" type="submit" name="update" label="Update" />
</lightning:recordEditForm>
It looks like below and even the Update-button works as expected and saves the record:
But what I really want is
<lightning:recordEditForm recordId="{!v.recordId}" objectApiName="{!v.ParentType}">
Note the {!v.ParentType} instead of the hardcoded "Order"
As an great unfortunate, this only collapses to that error-popup
In the screenshot you see, that the ParentType is correctly bound to v.ParentType (right above the button) which a I also verify in the console
Suspicion
I set the ParentType-attribute as a result of APEX call (asynchronously). This seems to be too late for the lightning:recordEditForm. It tries to render with objectApiName at a time where it is still blank, hence it crashes during initialization…
Question
Is there a clean way to avoid this and get something to fly with an dynamic objectApiName?
Trying to use $A.createComponents()
As @sfdcfox suggested I jump on the $A.createComponents() which turned indeed out to be tricky, exactly as sfdcfox has predicted. Im following this documentation here.
Added a button to the markup
Added a handler to the js-controller:
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);
}
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 press the button – 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 get output and the attribute are holding good values.
Best Answer
So I faced a similar issue, I managed to solve it using aura:if
aura:if doesnt create the inner components unless the condition is true. You can use it to your advantage.
Thus when your component is loaded even before calling init event, lightning:recordEditForm wont render as v.ParentType will be null.
After your init is called and you set the value of v.ParentType then automatically it will start rendering the lightning:recordEditForm. As ParentType is not null, it wont throw an ugly error.
SRC: https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/components_conditional_markup.htm