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 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 by 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 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 unsupported type. This runtime error will be turned into the compile-time one, once the required Rust feature is stabilized.

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 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 the 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 E struct to eliminate boilerplate and improve safety and readability. You can find API drafts in this issue.