Marko

Events

Marko supports listening to browser events on native tags as well as custom events from custom tags using the same API.

Listening to events

All events emitted from native and custom tags can be received by using an on-* attribute in combination with the attribute arguments syntax.

The first argument for the attribute must be a function or a string that maps to a predefined method on the component's class.

Method handler

When a string is provided as the first argument Marko will look for a method on the component's class and call that.

class {
  log(msg) {
    ...
  }
 
  logChange(newTab) {
    this.log(`changed to: ${newTab}`);
  }
}
 
<my-tabs on-switch-tab("logChange")>
  ...
</my-tabs>

When my-tabs emits the switch-tab event it will call the logChange method on this component. The benefit here is that within the handler you will have access to the current component instance and be able to read data, emit events, update state, etc.

Function handler

You can provide a function as the first argument of the on-* attribute. This function will be called whenever the event is fired. Below we use the static syntax to define a function and use that.

static function handleClick(event) {
  event.preventDefault();
  console.log("Clicked!");
}
 
<button on-click(handleClick)>
  ...
</button>
static function handleClick(event) {
  event.preventDefault();
  console.log("Clicked!");
}
 
button on-click(handleClick) -- ...

In the above example, any time the <button> is clicked the handleClick function is called.

You can also use an inline arrow function, or anything that evaluates to a function:

<button on-click((event) => {
  console.log("Clicked!");
})>
  ...
</button>
button on-click(event => {
  console.log("Clicked!");
}) -- ...

Binding additional arguments

Arguments after the handler will be prepended when the handler is called.

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>
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}

Here we can share the logic for removeFriend with each friend in the list. When a <button> is clicked, the id of the friend being removed is passed into the removeFriend handler followed by the DOM click event.

Emitting custom events

The recommended way for a custom tag to communicate with it's parent is through custom events.

All components implement a node.js style event emitter API, which is used to emit events to its parent component.

email-input.marko
class {
  handleChange(event) {
    const email = event.target.value;
    const isValid = /\@/g.test(email);
 
    if (isValid) {
      // Only emit email changes if they are valid.
      this.emit("email-change"{ email: email });
    }
  }
}
 
<input name=input.name on-change("handleChange")/>
class {
  handleChange(event) {
    const email = event.target.value;
    const isValid = /\@/g.test(email);
 
    if (isValid) {
      // Only emit email changes if they are valid.
      this.emit("email-change"{ email: email });
    }
  }
}
 
input name=input.name on-change("handleChange")

The above example component is listening to native change events from the <input> element, and then emitting it's own email-change event if it decides that the change was valid.

<form>
  <email-input name="email" on-email-change(...)/>
</form>
form
  email-input name="email" on-email-change(...)

Note: Events are not recieved as input (you cannot access input.onEmailChange), instead these setup subscriptions.

EDIT

Contributors

Helpful? You can thank these awesome people! You can also edit this doc if you see any issues or want to improve it.