No way to listen to custom events exposed by custom elements
Tracking issue for the point, "Custom events" described in https://github.com/yewstack/yew/issues/1666
Problem
Yew should allow users to listen to custom events as well and pass CustomEvent to the callback.
There should be a way to deal with names like the ones used here. It can be a function on NodeRef or special syntax in html!, not 100% sure on the API.
from #1666
Questionnaire
- [ ] I'm interested in fixing this myself but don't know where to start
- [ ] I would like to fix and I have a solution
- [x] I don't have time to fix this right now, but maybe later
I apologize it took me so long to create this issue after being requested here (https://github.com/yewstack/yew/issues/1666#issuecomment-765852652)
I created a discussion to discuss potential solutions: https://github.com/yewstack/yew/discussions/1779
For a NodeRef version I first thought of something like this:
pub fn attach_event_listener<S, E>(
&self,
event: S,
callback: Callback<E>,
) -> Option<gloo::events::EventListener>
where
S: Into<std::borrow::Cow<'static, str>>,
E: AsRef<web_sys::Event> + JsCast + 'static,
{
use gloo::events::*;
let event_target: EventTarget = self.get()?.into();
match &callback {
Callback::Callback { passive, .. } => {
let passive = passive.unwrap_or_default();
let listener = EventListener::new_with_options(
&event_target,
event,
EventListenerOptions {
phase: EventListenerPhase::Bubble,
passive,
},
move |e| callback.emit(e.clone().unchecked_into()),
);
Some(listener)
}
Callback::CallbackOnce(_) => {
let listener = EventListener::once(&event_target, event, move |e| {
callback.emit(e.clone().unchecked_into())
});
Some(listener)
}
}
}
We'd probably avoid leaking the gloo::events::EventListener type in the actual impl but just makes this example bit easier to read :)
Then in the rendered function of a component you might do something like this:
fn rendered(&mut self, ctx: &Context<Self>) {
match (self.node_ref.get(), self.click_listener.as_ref()) {
(None, Some(_)) => {
// element has not been rendered so remove old listener
self.click_listener.take();
}
(Some(_), None) => {
// element has been rendered and no event listener has been attached
// so add one this time.
self.click_listener = self.node_ref.attach_event_listener(
"click",
ctx.link().callback(|_: yew::MouseEvent| Msg::Increment),
);
}
// either the element is not rendered and there is no old listener OR
// both the element and listener are still set - with both we do nothing :)
_ => {}
}
}
Also #1991 even though closed I have solved the hiccup and I'm currently keeping it up to date in my fork just in case there was any interest in that :)
Sorry for the accidental closing 😢
Is there no workaround for this issue :cry: ? newbie here
@dfenerski Check the documentation here I think that should work. But I'm also new to Yew and would really like to see this solved in an easier way... @hamza1311 Has anything happened here after the discussion #1779 ?