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
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 by 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 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 unsupported type. This runtime error will be turned into the compile-time one, once the required Rust feature is stabilized.
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:
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 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.
They will be discussed in other chapters, however you can take inspiration from examples window_events and subscribe.
*ev
functions will be replaced with E
struct to eliminate boilerplate and improve safety and readability. You can find API drafts in this issue.