1 | # Events
|
2 |
|
3 | Marko’s event API supports:
|
4 |
|
5 | - [Browser events](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Events) on native tags
|
6 | - Custom events from [custom tags](./custom-tags.md)
|
7 |
|
8 | Note that **you can’t mix event targets and event types**: custom tags can only listen for custom events, and native tags can only listen for native events.
|
9 |
|
10 | ## Listening to events
|
11 |
|
12 | Both kinds of events are received with an `on-*` attribute and the [attribute arguments syntax](./syntax.md#arguments):
|
13 |
|
14 | ```marko
|
15 | <input type="checkbox"
|
16 | on-change=(event => console.info(`Checked? ${event.target.checked}`))
|
17 | />
|
18 | ```
|
19 |
|
20 | The [first argument for the attribute can be a function](#function-handler), or [a string matching a method name](#method-handler) on the [component’s `class` declaration](./class-components.md).
|
21 |
|
22 | ### Function handler
|
23 |
|
24 | 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.
|
25 |
|
26 | Below we use the [`static` prefix](./syntax.md#static-javascript) to define a function, then use it as a `click` handler:
|
27 |
|
28 | ```marko
|
29 | static function handleClick(event) {
|
30 | event.preventDefault();
|
31 | console.log("Clicked!");
|
32 | }
|
33 |
|
34 | <button on-click(handleClick)>
|
35 | Log click
|
36 | </button>
|
37 | ```
|
38 |
|
39 | In the above example, any time the `<button>` is clicked the `handleClick` function is called.
|
40 |
|
41 | You can also use an inline arrow function:
|
42 |
|
43 | ```marko
|
44 | <button on-click(() => alert("Clicked! 🎉"))>
|
45 | Celebrate click
|
46 | </button>
|
47 | ```
|
48 |
|
49 | …or anything that evaluates to a function:
|
50 |
|
51 | ```marko
|
52 | const handler = input.dontBreakMyApp ?
|
53 | () => console.error("Clicked!") :
|
54 | () => { throw Error("Clicked!") }
|
55 |
|
56 | <button on-click(handler)>
|
57 | Do not click
|
58 | </button>
|
59 | ```
|
60 |
|
61 | ### Method handler
|
62 |
|
63 | When a string is the first argument, Marko calls a matching method on the component's `class`.
|
64 |
|
65 | ```marko
|
66 | class {
|
67 | logChange(newTab) {
|
68 | console.log(`changed to: ${newTab}`);
|
69 | }
|
70 | }
|
71 |
|
72 | <my-tabs on-switch-tab("logChange")>
|
73 | …
|
74 | </my-tabs>
|
75 | ```
|
76 |
|
77 | When `<my-tabs>` emits the `switch-tab` event, it will call its `logChange` method.
|
78 |
|
79 | Within the handler you can access the current component instance, read data, emit events, update state, etc.
|
80 |
|
81 | ### Binding additional arguments
|
82 |
|
83 | Arguments after the handler are prepended when the handler is called:
|
84 |
|
85 | ```marko
|
86 | static function removeFriend(friendId, event) {
|
87 | event.preventDefault();
|
88 | window.myAPI.unfriend(friendId);
|
89 | }
|
90 |
|
91 | <for|friend| of=input.friends>
|
92 | <button on-click(removeFriend, friend.id)>
|
93 | Unfriend ${friend.name}
|
94 | </button>
|
95 | </for>
|
96 | ```
|
97 |
|
98 | 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.
|
99 |
|
100 | ## Emitting custom events
|
101 |
|
102 | The recommended way for a [custom tag](./custom-tags.md) to communicate with its parent is through **custom events**.
|
103 |
|
104 | All components implement a [Node.js-style event emitter](https://nodejs.org/api/events.html#events_class_eventemitter) to send events to parent components.
|
105 |
|
106 | _email-input.marko_
|
107 |
|
108 | ```marko
|
109 | class {
|
110 | handleChange(event) {
|
111 | if (event.target.validity.valid) {
|
112 | // Only emit email-changes if they are valid.
|
113 | this.emit("email-change", { email: event.target.value });
|
114 | }
|
115 | }
|
116 | }
|
117 |
|
118 | <input type="email" name=input.name on-change("handleChange")/>
|
119 | ```
|
120 |
|
121 | 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.
|
122 |
|
123 | ```marko
|
124 | <form>
|
125 | <email-input name="email" on-email-change(...)/>
|
126 | </form>
|
127 | ```
|
128 |
|
129 | > **Note:** Events are not received as `input`; you cannot access `input.onEmailChange`. Instead, they set up subscriptions.
|