Add ember-best-practices skill

This commit is contained in:
2026-04-01 12:59:41 +04:00
parent 913d5c915c
commit ecbac12440
65 changed files with 19863 additions and 0 deletions

View File

@@ -0,0 +1,132 @@
---
title: Use {{on}} Modifier for Event Handling
impact: MEDIUM
impactDescription: Better memory management and clarity
tags: events, modifiers, on, performance
---
## Use {{on}} Modifier for Event Handling
Use the `{{on}}` modifier for event handling instead of traditional action handlers for better memory management and clearer code.
**Incorrect (traditional action attribute):**
```glimmer-js
// app/components/button.gjs
import Component from '@glimmer/component';
import { action } from '@ember/object';
class Button extends Component {
@action
handleClick() {
this.args.onClick?.();
}
<template>
<button onclick={{this.handleClick}}>
{{@label}}
</button>
</template>
}
```
**Correct (using {{on}} modifier):**
```glimmer-js
// app/components/button.gjs
import Component from '@glimmer/component';
import { on } from '@ember/modifier';
class Button extends Component {
handleClick = () => {
this.args.onClick?.();
};
<template>
<button {{on "click" this.handleClick}}>
{{@label}}
</button>
</template>
}
```
**With event options:**
```glimmer-js
// app/components/scroll-tracker.gjs
import Component from '@glimmer/component';
import { on } from '@ember/modifier';
class ScrollTracker extends Component {
handleScroll = (event) => {
console.log('Scroll position:', event.target.scrollTop);
};
<template>
<div class="scrollable" {{on "scroll" this.handleScroll passive=true}}>
{{yield}}
</div>
</template>
}
```
**Multiple event handlers:**
```glimmer-js
// app/components/input-field.gjs
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { on } from '@ember/modifier';
class InputField extends Component {
@tracked isFocused = false;
handleFocus = () => {
this.isFocused = true;
};
handleBlur = () => {
this.isFocused = false;
};
handleInput = (event) => {
this.args.onInput?.(event.target.value);
};
<template>
<input
type="text"
class={{if this.isFocused "focused"}}
{{on "focus" this.handleFocus}}
{{on "blur" this.handleBlur}}
{{on "input" this.handleInput}}
value={{@value}}
/>
</template>
}
```
**Using fn helper for arguments:**
```glimmer-js
// app/components/item-list.gjs
import { fn } from '@ember/helper';
import { on } from '@ember/modifier';
<template>
<ul>
{{#each @items as |item|}}
<li>
{{item.name}}
<button {{on "click" (fn @onDelete item.id)}}>
Delete
</button>
</li>
{{/each}}
</ul>
</template>
```
The `{{on}}` modifier properly cleans up event listeners, supports event options (passive, capture, once), and makes event handling more explicit.
Reference: [Ember Modifiers - on](https://guides.emberjs.com/release/components/template-lifecycle-dom-and-modifiers/#toc_event-handlers)