Can't cancel event propagation in Yew 0.20
Problem
Relevant code: https://github.com/yozhgoor/yewprint/blob/update-dependencies/src/tree.rs#L297-L317
In Yewprint I have a <Tree/> component which I replicated from the JS code of Blueprint. As you can see here, the onclick event is bound on a div and on a child node:
<div
class="bp3-tree-node-content"
style={content_style}
onclick={self.handler_click.clone()}
>
// ...
<Icon
class={classes!(class.to_string())}
icon={IconName::ChevronRight}
onclick={self.handler_caret_click.clone()}
/>
The way it is normally handled (by Blueprint and thus by Yewprint) is to stop the propagation of the click event if the click event occurred on the caret. As you can see here:
match msg {
TreeNodeMessage::CaretClick(event) => {
if ctx.props().is_expanded {
if let Some(on_collapse) = ctx.props().on_collapse.as_ref() {
event.stop_propagation(); <--- here
on_collapse.emit((ctx.props().node_id.clone(), event));
}
} else if let Some(on_expand) = ctx.props().on_expand.as_ref() {
event.stop_propagation(); <--- here
on_expand.emit((ctx.props().node_id.clone(), event));
}
}
TreeNodeMessage::Click(event) => {
if let Some(onclick) = ctx.props().onclick.as_ref() {
onclick.emit((ctx.props().node_id.clone(), event));
}
}
}
This is in par with Blueprint's code: https://github.com/palantir/blueprint/blob/a8b99210bfb1510d9164f9a59a5103d555c75447/packages/core/src/components/tree/treeNode.tsx#L188
This is working properly with Yew 0.19 but it is somehow broken in Yew 0.20.
I'm not sure what could be possibly the cause here or if it should be considered as a bug at all. If someone could give me a few pointers...
Steps To Reproduce
- Clone the source code of yozhgoor's fork:
git clone https://github.com/yozhgoor/yewprint.git - Change dir:
cd yewprint - Checkout to the commit where the issue occurs:
git checkout --detach 4fc68f4b - Run the dev server:
cargo xtask start(no build tool required to install) - Connect to the dev server: http://localhost:8000/tree
You can do the same with Yew 0.19 by cloning https://github.com/yewprint/yewprint.git instead.
Expected behavior
When clicking on the caret, the menu item should not highlight.
Actual behavior
When clicking on the caret, the menu item highlight.
Screenshots

Environment:
- Yew version: 0.20
- Rust version: 1.65.0
- Target: wasm32-unknown-unknown
- Build tool: xtask-wasm (nothing to install)
- OS: Linux
- Browser and version, if relevant: Firefox 107.0.1
Questionnaire
- [x] I'm interested in fixing this myself but don't know where to start
- [ ] I would like to fix and I have a solution
- [ ] I don't have time to fix this right now, but maybe later
(I made this terrible workaround in the meantime... it works https://github.com/yozhgoor/yewprint/commit/cafc2a7149b8f73fabdb12facadec71ef3426ee5 )
This might be because of changes to message propagation and how they're processed. Iirc, they used to be sent and handled immediately, but now are only sent and later processed. Which means that your call to stop_propagation occurs too late and only after the event has already bubbled through the vdom.
I knew it would be something like that!
I suppose there isn't much fix to do here. Reverting is probably impossible at this point. Do we have an alternative solution for this kind of situation?
If event default behavior and/or propagation couldn't be stopped from within a component message handler, it would break my app, although I can simply refactor the prevent_default/stop_propagation into the event handler as opposed to the component message handler.
I suppose there isn't much fix to do here.
An initial mitigation strategy would be to mention this in the migration guide.
An extra sentence under message batching couldn't hurt. What I'm still not so sure about is why so much of the event handling is happening in update. That is good for mutating your own component, but wouldn't a workable strategy here be to put all that work in the handler directly before even sending a message to your component - well I guess the props are not so easily accessible there?
I just tested my application and prevent_default in my component message handler still works somehow (note that it wouldn't work if there was even as much as 0ms delay e.g. window.onkeydown = e => { setTimeout(() => e.preventDefault(), 0) };). It's a bit harder to test stop_propagation but I'll see what I can do.
@finnbear the message processing still happens in the same tick, i.e. the scheduler is still started as part of the event handling and will run to completion before control is returned to the browser, so prevent_default still works. But bubbling happens before message processing, so stop_propagation would happen too late.
I think I am running into the same problem. Is there any kind of solution for this?
I think I am running into the same problem. Is there any kind of solution for this?
Currently in Yewprint we are delaying the events using Timeouts as you can see here:
https://github.com/yewprint/yewprint/blame/a705c43/src/tree.rs#L218-L219
https://github.com/yewprint/yewprint/blame/a705c43/src/tree.rs#L284-L299
https://github.com/yewprint/yewprint/blame/a705c43/src/tree.rs#L373-L378
https://github.com/yewprint/yewprint/blame/a705c43/src/tree.rs#L368
Timeouts being cancellable, this work just fine.