Description
Modifier Manager should provide a hook, which has access to the DOM element but is executed before the element is insert into the DOM.
The installModifier
hook is executed after the element is insert into the DOM:
This hook has the following timing semantics:
Always
- called after all children modifier managers installModifer hook are called
- called after DOM insertion
The createModifier
hook does not have access to the DOM element. Accordingly to Modifier Manager RFC "called as discovered during DOM construction". Not sure if the element is created yet and just not passed in or does not even exist yet.
I have two use cases for a hook, which has access to the DOM element but is executed before it's insert into the DOM:
- A
set-attribute
andset-property
modifier, which sets values as attributes or properties on the element before it's insert into the DOM. - The existing
ember-style-modifier
, which manipulates the CSS styles of an element using CSSOM.
For both of them running before the element is insert into the DOM is important from a performance perspective. If executed after the element has been insert into the DOM the browser may do an unnecessary layout calculation in between. E.g. if Element.getBoundingClientRect()
or a similar function is called in between.
It's even worse as there isn't any garantuee if the modifier is executed in the same tick as the DOM insertion:
May or May Not
- be called in the same tick as DOM insertion
If it's executed in the next queue the Browser paint the state before the modifiers has been run. This may be visible to the end-user as an inconsistent and flickering UI.
Especially for set-attribute
and set-property
the timing is also important if considering custom elements. Custom elements are part of the web components feature set. Similar to @ember/component
they have lifecycle hooks. One of them is the connectedCallback
. It's executed when the element is insert into the DOM.
As modifiers are called only after the DOM element has been insert into the DOM manipulation attributes or properties set on the element using them are not available yet in connectedCallback
. I have created a JSFiddle to illustrate the timing relevance: https://jsfiddle.net/jv0Lk3sb/ It's creating a custom element, which implements the connectedCallback
. It sets two attributes on the custom element. One before and one after it has been insert into the DOM. Only the first one is available in connectedCallback
.
The limitation for custom elements is especially relevant as one can not rely on Glimmer VM always setting values passed as attributes as attributes. Depending on the custom element it may be set as an attribute or a property. It may even change between first and subsequent runs. See this issue for more details. Modifier would be a good solution to get full control if the values are set as an attribute or a property on the element. But due to their timing issue with connectedCallback
this is not possible in many cases.
While going this route we may want to consider allowing to run code with a modifier on destruction before the element is removed from DOM.
Thanks a lot to @rwjblue for the input on Discord, which helped creating this issue. I hope I got everything right.