Event Handlers

Event handlers ev, mouse_ev, etc. represent HTML EventListeners in the Seed world, e.g.:

button![
    model, 
    ev(Ev::Click, |_| Msg::Increment),
]

becomes

<button>15</button>

where a click on the button invokes your update function with Msg::Increment as an argument.

ev

ev is the basic event handler. The most common usage is:

ev(Ev::Click, |_| Msg::Increment)

Event

The first argument (Ev::Click) is called event or trigger.

It can be any Ev variant or you can write a custom one with Ev::from("custom_event"). Custom events may be useful in combination with custom elements.

Callback

The second argument(|_| Msg::Increment) is called callback or handler.

ev's callback expects web_sys::Event as an input. Event is the most general interface for all events. It's useful for calling methods like preventDefault:

ev(Ev::Click, |event| {
    event.prevent_default();
    Msg::LoginClicked
})
What is
web_sys?

web_sys crate is basically a Rust interface for Web APIs. You'll see it in many examples and docs. It's automatically imported from seed. However the Seed's one doesn't cover all Web APIs - when the compiler can't find a method, but you are sure web_sys supports it, you'll have to enable corresponding web_sys's features - see Cargo.toml in user_media example. You'll find the required features in web_sys docs - e.g. HtmlMediaElement.

You can return from callbacks:

  1. Msg
ev(Ev::Click, |_| Msg::Clicked),
ev(Ev::from("data-loaded"), Msg::DataLoaded`) // `enum Msg { DataLoaded(web_sys:Event) }`
  1. Option<Msg>
ev(Event::Click, |_| Some(Msg::Clicked))
  1. ()
ev(Ev::Click, |event| log!("Clicked!", event)),
ev(Ev::Click, |event| {
    event.prevent_default();
    event.stop_propagation();
})

Note: The app panics when you try to return an unsupported type. Once the required Rust feature is stabilized, this runtime error will be turned into a compile-time error.

Event Casting & Helpers

There are many specialized event types like MouseEvent and KeyboardEvent. However, we receive only Event in our ev callbacks - we need to cast the general Event to a concrete event sub-type to use its associated methods:

ev(Ev::Click, |event| {
    let mouse_event: web_sys::MouseEvent = event.unchecked_into();
    log!(mouse_event.ctrl_key());
}),
ev(Ev::Click, |event| {
    IF!(event.unchecked_into::<web_sys::MouseEvent>().shift_key() => Msg::Increment)
})

unchecked_into is one of the casting methods.

Note: Syntax ::<web_sys::MouseEvent> is known as a turbofish.

To eliminate error-prone boilerplate introduced by casting, there are some ev-related functions that cast the event before they call your callback:

There is one exception: input_ev. It doesn't cast Event into InputEvent - it tries to get the value directly from the element, because in most cases you just want to know the changed value and InputEvent doesn't contain it for some reasons. Example:

enum Msg {
    EmailChanged(String),
}
...

input![
    attrs! {
        At::Value => model.email
    },
    input_ev(Ev::Input, Msg::EmailChanged)
],

Note: All helpers panic if it's not possible to cast the event to the required event type.

Window / Document Events

They will be discussed in other chapters, however you can take inspiration from examples window_events and subscribe.

Future

*ev functions will be replaced with an E struct to eliminate boilerplate and improve safety and readability. You can find API drafts in this issue.