132 lines
3.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Events
Markos event API supports:
- [Browser events](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Events) on native tags
- Custom events from [custom tags](./custom-tags.md)
Note that **you cant mix event targets and event types**: custom tags can only listen for custom events, and native tags can only listen for native events.
## Listening to events
Both kinds of events are received with an `on-*` attribute and the [attribute arguments syntax](./syntax.md#arguments):
```marko
<input type="checkbox"
on-change(event => console.info(`Checked? ${event.target.checked}`))
/>
```
The [first argument for the attribute can be a function](#function-handler), or [a string matching a method name](#method-handler) on the [components `class` declaration](./class-components.md).
### Function handler
If you provide a function as the first argument of the `on-*` attribute, the function is called whenever the event fires, like standard event listeners.
Below we use the [`static` prefix](./syntax.md#static-javascript) to define a function, then use it as a `click` handler:
```marko
static function handleClick(event) {
event.preventDefault();
console.log("Clicked!");
}
<button on-click(handleClick)>
Log click
</button>
```
In the above example, any time the `<button>` is clicked the `handleClick` function is called.
You can also use an inline arrow function:
```marko
<button on-click(() => alert("Clicked! 🎉"))>
Celebrate click
</button>
```
…or anything that evaluates to a function:
```marko
$ const handler = (
input.dontBreakMyApp ?
() => console.error("Clicked!") :
() => { throw Error("Clicked!") }
);
<button on-click(handler)>
Do not click
</button>
```
### Method handler
When a string is the first argument, Marko calls a matching method on the component's `class`.
```marko
class {
logChange(newTab) {
console.log(`changed to: ${newTab}`);
}
}
<my-tabs on-switch-tab("logChange")>
</my-tabs>
```
When `<my-tabs>` emits the `switch-tab` event, it will call its `logChange` method.
Within the handler you can access the current component instance, read data, emit events, update state, etc.
### Binding additional arguments
Arguments after the handler are prepended when the handler is called:
```marko
static function removeFriend(friendId, event) {
event.preventDefault();
window.myAPI.unfriend(friendId);
}
<for|friend| of=input.friends>
<button on-click(removeFriend, friend.id)>
Unfriend ${friend.name}
</button>
</for>
```
Here we share the logic for `removeFriend()` with each `friend` in the `friends` array. When the `<button>` is clicked, the `id` of the removed `friend` is passed to the `removeFriend()`, handler followed by the DOM `click` event.
## Emitting custom events
The recommended way for a [custom tag](./custom-tags.md) to communicate with its parent is through **custom events**.
All components implement a [Node.js-style event emitter](https://nodejs.org/api/events.html#events_class_eventemitter) to send events to parent components.
_email-input.marko_
```marko
class {
handleChange(event) {
if (event.target.validity.valid) {
// Only emit email-changes if they are valid.
this.emit("email-change", { email: event.target.value });
}
}
}
<input type="email" name=input.name on-change("handleChange")/>
```
The above code listens to native `change` events from the `<input>` element, and then emits its own `email-change` event if the change was valid.
```marko
<form>
<email-input name="email" on-email-change("...")/>
</form>
```
> **Note:** Events are not received as `input`; you cannot access `input.onEmailChange`. Instead, they set up subscriptions.