I have now solved this issue in my app. The root cause was that I am using dynamically created components and I wasn't explicitly declaring them as dependencies in their parent component. So I had code like this:
$A.createComponent(
"c:officeHoursTable",
{
"contactList": component.get("v.contactOfficeHours")
},
function(newList) {
if (component.isValid()) {
var cell = component.find("officeHoursPlaceholder");
cell.set("v.body", newList);
}
}
);
My c:officeHoursTable
was not declared as dependency, so createComponent
was going to the server to create the component. It was on the server that in some cases I was hitting the limit on the number of components that can be created.
I had seen the "10,000 components" limit talked about, but I hadn't seen the detail on it as documented by Salesforce:
There’s no limit in component creation on the client side. You can create up to 10,000 components in one server request. If you hit this limit, ensure that you’re creating components on the client side in markup or in JavaScript using $A.createComponent()
or $A.createComponents()
. To avoid a trip to the server for component creation in JavaScript code, add an <aura:dependency>
tag for the component in the markup to explicitly tell the framework about the dependency.
So there is no limit on the client side, but there is a limit on the server side.
The fix
To fix the problem, I just added a dependancy definiton to the component that is dynamically creating my officeHoursTable
component:
<aura:dependency resource="markup://c:officeHoursTable" />
That stops Aura ever going to the server to create the officeHoursTable
component and the problem goes away.
I have a couple of questions that I still don't really definitively know the answer to:
Why was I hitting the limit ?
I still don't know why I was hitting the limit. With my understanding of what I component is, when I was rendering data for 40 contacts my officeHoursTable
component was creating around 1,000 components. That is an order of magnitude lower than the stated limit.
My component doesn't nest any of my other components, it uses: aura:if
, aura:iteration
, and ui:outputText
.
My best guess is that my understanding of what counts as a component is wrong. I'm guessing that every expression in an HTML attribute counts against the component limit.
Looking at the Aura source it looks to me like expressions are indeed aura:expression
components, which in turn instantiate aura:text
components to render their output. Which probably makes hitting 10,000 components not too hard.
In that case, then my 40 record test case would hit the limit every time.
Which brings me to the next question:
Why was it intermittent ?
The issue appeared very much intermittent, sometimes my 40 record test case would render without problem.
My best guess is that when the 40 record test case was working, it was because I had already loaded the officeHoursTable
component with a smaller number of records that didn't trigger the limit. Once the component has been created on the server successfully once the framework doesn't go back to the server when asked to create another instance of the component.
And the last outstanding question:
Why has it started happening now ?
As best as I can tell this wasn't happening with my same code last week, this component creation error only appeared to start happening recently. I'm guessing an update to the framework was rolled out that somehow changed how the limit is applied.
Best Answer
You are hitting a timing issue with init that is by design - you should not use component.getElement() in init because elements are not reliably available in init handlers - you'll want to look into using a custom renderer afterRender method which gets called at a point where you are guaranteed to have actual DOM elements available and was designed for exactly this ind of scenario.
https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/js_renderers.htm