mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
392dc0131a
Fun: the transition is handled at two different places, once for dom nodes, once for components. Obviously, I only applied the change to the first case and forgot about the second.
152 lines
5.0 KiB
Markdown
152 lines
5.0 KiB
Markdown
# 🦉 Event Handling 🦉
|
|
|
|
## Content
|
|
|
|
- [Event Handling](#event-handling)
|
|
- [Business DOM Events](#business-dom-events)
|
|
- [Inline Event Handlers](#inline-event-handlers)
|
|
- [Modifiers](#modifiers)
|
|
|
|
## Event Handling
|
|
|
|
In a component's template, it is useful to be able to register handlers on DOM
|
|
elements to some specific events. This is what makes a template _alive_. There
|
|
are four different use cases.
|
|
|
|
1. Register an event handler on a DOM node (_pure_ DOM event)
|
|
2. Register an event handler on a component (_pure_ DOM event)
|
|
3. Register an event handler on a DOM node (_business_ DOM event)
|
|
4. Register an event handler on a component (_business_ DOM event)
|
|
|
|
A _pure_ DOM event is directly triggered by a user interaction (e.g. a `click`).
|
|
|
|
```xml
|
|
<button t-on-click="someMethod">Do something</button>
|
|
```
|
|
|
|
This will be roughly translated in javascript like this:
|
|
|
|
```js
|
|
button.addEventListener("click", component.someMethod.bind(component));
|
|
```
|
|
|
|
The suffix (`click` in this example) is simply the name of the actual DOM
|
|
event.
|
|
|
|
## Business DOM Events
|
|
|
|
A _business_ DOM event is triggered by a call to `trigger` on a component.
|
|
|
|
```xml
|
|
<MyComponent t-on-menu-loaded="someMethod" />
|
|
```
|
|
|
|
```js
|
|
class MyComponent {
|
|
someWhere() {
|
|
const payload = ...;
|
|
this.trigger('menu-loaded', payload);
|
|
}
|
|
}
|
|
```
|
|
|
|
The call to `trigger` generates an `OwlEvent`, a subclass of [_CustomEvent_](https://developer.mozilla.org/docs/Web/Guide/Events/Creating_and_triggering_events)
|
|
with an additional attribute `originalComponent` (the component that triggered
|
|
the event). The generated event is of type `menu-loaded` and dispatches it on
|
|
the component's DOM element (`this.el`). The event bubbles and is cancelable.
|
|
The parent component listening to event `menu-loaded` will receive the payload
|
|
in its `someMethod` handler (in the `detail` property of the event), whenever
|
|
the event is triggered.
|
|
|
|
```js
|
|
class ParentComponent {
|
|
someMethod(ev) {
|
|
const payload = ev.detail;
|
|
...
|
|
}
|
|
}
|
|
```
|
|
|
|
By convention, we use KebabCase for the name of _business_ events.
|
|
|
|
The `t-on` directive allows to prebind its arguments. For example,
|
|
|
|
```xml
|
|
<button t-on-click="someMethod(expr)">Do something</button>
|
|
```
|
|
|
|
Here, `expr` is a valid Owl expression, so it could be `true` or some variable
|
|
from the rendering context.
|
|
|
|
### Type Hinting
|
|
|
|
Note that if you work with Typescript, the `trigger` method is generic on the type of the payload.
|
|
|
|
You can then describe the type of the event, so you will see typing errors...
|
|
|
|
```typescript
|
|
this.trigger<MyCustomPayload>("my-custom-event", payload);
|
|
```
|
|
|
|
```typescript
|
|
myCustomEventHandler(ev: OwlEvent<MyCustomPayload>) { ... }
|
|
```
|
|
|
|
## Inline Event Handlers
|
|
|
|
One can also directly specify inline statements. For example,
|
|
|
|
```xml
|
|
<button t-on-click="state.counter++">Increment counter</button>
|
|
```
|
|
|
|
Here, `state` must be defined in the rendering context (typically the component)
|
|
as it will be translated to:
|
|
|
|
```js
|
|
button.addEventListener("click", () => {
|
|
context.state.counter++;
|
|
});
|
|
```
|
|
|
|
Warning: inline expressions are evaluated in the context of the template. This
|
|
means that they can access the component methods and properties. But if they set
|
|
a key, the inline statement will actually not modify the component, but a key in
|
|
a sub scope.
|
|
|
|
```xml
|
|
<button t-on-click="value = 1">Set value to 1 (does not work!!!)</button>
|
|
<button t-on-click="state.value = 1">Set state.value to 1 (work as expected)</button>
|
|
```
|
|
|
|
## Modifiers
|
|
|
|
In order to remove the DOM event details from the event handlers (like calls to
|
|
`event.preventDefault`) and let them focus on data logic, _modifiers_ can be
|
|
specified as additional suffixes of the `t-on` directive.
|
|
|
|
| Modifier | Description |
|
|
| ---------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
| `.stop` | calls `event.stopPropagation()` before calling the method |
|
|
| `.prevent` | calls `event.preventDefault()` before calling the method |
|
|
| `.self` | calls the method only if the `event.target` is the element itself |
|
|
| `.capture` | bind the event handler in [capture](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) mode. |
|
|
|
|
```xml
|
|
<button t-on-click.stop="someMethod">Do something</button>
|
|
```
|
|
|
|
Note that modifiers can be combined (ex: `t-on-click.stop.prevent`), and that
|
|
the order may matter. For instance `t-on-click.prevent.self` will prevent all
|
|
clicks while `t-on-click.self.prevent` will only prevent clicks on the element
|
|
itself.
|
|
|
|
Finally, empty handlers are tolerated as they could be defined only to apply
|
|
modifiers. For example,
|
|
|
|
```xml
|
|
<button t-on-click.stop="">Do something</button>
|
|
```
|
|
|
|
This will simply stop the propagation of the event.
|