Skip to content

Allow modifiers to interact with the element before it is insert into the DOM #652

Open
@jelhan

Description

@jelhan

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

https://github.com/emberjs/rfcs/blob/master/text/0373-Element-Modifier-Managers.md#installmodifier

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:

  1. A set-attribute and set-property modifier, which sets values as attributes or properties on the element before it's insert into the DOM.
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions