2.9 KiB
2.9 KiB
title, impact, impactDescription, tags
| title | impact | impactDescription | tags |
|---|---|---|---|
| Use Modifiers for DOM Side Effects | LOW-MEDIUM | Better separation of concerns | modifiers, dom, lifecycle, advanced |
Use Modifiers for DOM Side Effects
Use modifiers (element modifiers) to handle DOM side effects and lifecycle events in a reusable, composable way.
Incorrect (manual DOM manipulation in component):
// app/components/chart.gjs
import Component from '@glimmer/component';
class Chart extends Component {
chartInstance = null;
constructor() {
super(...arguments);
// Can't access element here - element doesn't exist yet!
}
willDestroy() {
super.willDestroy();
this.chartInstance?.destroy();
}
<template>
<canvas id="chart-canvas"></canvas>
{{! Manual setup is error-prone and not reusable }}
</template>
}
Correct (function modifier - preferred for simple side effects):
// app/modifiers/chart.js
import { modifier } from 'ember-modifier';
export default modifier((element, [config]) => {
// Initialize chart
const chartInstance = new Chart(element, config);
// Return cleanup function
return () => {
chartInstance.destroy();
};
});
Also correct (class-based modifier for complex state):
// app/modifiers/chart.js
import Modifier from 'ember-modifier';
import { registerDestructor } from '@ember/destroyable';
export default class ChartModifier extends Modifier {
chartInstance = null;
modify(element, [config]) {
// Cleanup previous instance if config changed
if (this.chartInstance) {
this.chartInstance.destroy();
}
this.chartInstance = new Chart(element, config);
// Register cleanup
registerDestructor(this, () => {
this.chartInstance?.destroy();
});
}
}
// app/components/chart.gjs
import chart from '../modifiers/chart';
<template>
<canvas {{chart @config}}></canvas>
</template>
Use function modifiers for simple side effects. Use class-based modifiers only when you need complex state management.
For commonly needed modifiers, use ember-modifier helpers:
// app/modifiers/autofocus.js
import { modifier } from 'ember-modifier';
export default modifier((element) => {
element.focus();
});
// app/components/input-field.gjs
import autofocus from '../modifiers/autofocus';
<template><input {{autofocus}} type="text" /></template>
Use ember-resize-observer-modifier for resize handling:
ember install ember-resize-observer-modifier
// app/components/resizable.gjs
import onResize from 'ember-resize-observer-modifier';
<template>
<div {{onResize this.handleResize}}>
Content that responds to size changes
</div>
</template>
Modifiers provide a clean, reusable way to manage DOM side effects without coupling to specific components.
Reference: Ember Modifiers