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
is the basic event handler. The most common usage is:
ev(Ev::Click, |_| Msg::Increment)
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.
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
})
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:
Msg
ev(Ev::Click, |_| Msg::Clicked),
ev(Ev::from("data-loaded"), Msg::DataLoaded`) // `enum Msg { DataLoaded(web_sys:Event) }`
Option<Msg>
ev(Event::Click, |_| Some(Msg::Clicked))
()
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.
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:
keyboard_ev
casts Event
to KeyboardEventmouse_ev
=> MouseEventtouch_ev
=> TouchEventdrag_ev
=> DragEventpointer_ev
=> PointerEventThere 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.
They will be discussed in other chapters, however you can take inspiration from examples window_events and subscribe.
*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.