Provides element modifiers that can be used to hook into specific portions of the rendering lifecycle.
- Ember.js v2.18 or above
- Ember CLI v2.13 or above
ember install @ember/render-modifiers
This sets the scroll position of an element, and updates it whenever the scroll position changes.
Before:
export default Component.extend({
classNames: ['scroll-container'],
didRender() {
this.element.scrollTop = this.scrollPosition;
}
});
After:
export default class Component.extend({
setScrollPosition(element, [scrollPosition]) {
element.scrollTop = scrollPosition;
}
})
This adds a CSS class to an alert element in a conditional whenever it renders to fade it in, which is a bit of an extra hoop. For CSS transitions to work, we need to append the element without the class, then add the class after it has been appended.
Before:
export default Component.extend({
didRender() {
let alert = this.element.querySelector('.alert');
if (alert) {
alert.classList.add('fade-in');
}
}
});
After:
export default Component.extend({
fadeIn(element) {
element.classList.add('fade-in');
}
});
One key thing to know about {{did-update}}
is it will not rerun whenever the
contents or attributes on the element change. For instance, {{did-update}}
will not rerun when @type
changes here:
If {{did-update}}
should rerun whenever a value changes, the value should be
passed as a parameter to the modifier. For instance, a textarea which wants to
resize itself to fit text whenever the text is modified could be setup like
this:
export default Component.extend({
resizeArea(element) {
element.style.height = `${element.scrollHeight}px`;
}
});
This is the type of rendering done by libraries like ember-leaflet
, which use
components to control the rendering of the library, but without any templates
themselves. The underlying library for this is here.
This is a simplified example of how you could accomplish this with Glimmer
components and element modifiers.
Node component:
// components/node.js
export default Component.extend({
init() {
super(...arguments);
this.children = new Set();
this.parent.registerChild(this);
}
willDestroy() {
super(...arguments);
this.parent.unregisterChild(this);
}
registerChild(child) {
this.children.add(child);
}
unregisterChild(child) {
this.children.delete(child);
}
didInsertNode(element) {
// library setup code goes here
this.children.forEach(c => c.didInsertNode(element));
}
willDestroyNode(element) {
// library teardown code goes here
this.children.forEach(c => c.willDestroyNode(element));
}
}
Root component:
// components/root.js
import NodeComponent from './node.js';
export default NodeComponent.extend();
Usage:
This project is licensed under the MIT License.