Do not stop prop is there is no prop to stop (#2116)
Check that desired event actions are defined on the object passed as the DOM event before calling them to avoid frontend errors.
This commit is contained in:
parent
6e71393ed5
commit
bf20a530df
@ -1,5 +1,6 @@
|
||||
"""Ensure stopPropagation and preventDefault work as expected."""
|
||||
|
||||
import asyncio
|
||||
from typing import Callable, Coroutine, Generator
|
||||
|
||||
import pytest
|
||||
@ -21,13 +22,31 @@ def TestEventAction():
|
||||
def on_click2(self):
|
||||
self.order.append("on_click2")
|
||||
|
||||
@rx.var
|
||||
def token(self) -> str:
|
||||
return self.get_token()
|
||||
class EventFiringComponent(rx.Component):
|
||||
"""A component that fires onClick event without passing DOM event."""
|
||||
|
||||
tag = "EventFiringComponent"
|
||||
|
||||
def _get_custom_code(self) -> str | None:
|
||||
return """
|
||||
function EventFiringComponent(props) {
|
||||
return (
|
||||
<div id={props.id} onClick={(e) => props.onClick("foo")}>
|
||||
Event Firing Component
|
||||
</div>
|
||||
)
|
||||
}"""
|
||||
|
||||
def get_event_triggers(self):
|
||||
return {"on_click": lambda: []}
|
||||
|
||||
def index():
|
||||
return rx.vstack(
|
||||
rx.input(value=EventActionState.token, is_read_only=True, id="token"),
|
||||
rx.input(
|
||||
value=EventActionState.router.session.client_token,
|
||||
is_read_only=True,
|
||||
id="token",
|
||||
),
|
||||
rx.button("No events", id="btn-no-events"),
|
||||
rx.button(
|
||||
"Stop Prop Only",
|
||||
@ -90,6 +109,18 @@ def TestEventAction():
|
||||
).stop_propagation.prevent_default,
|
||||
id="link-stop-propagation-prevent-default",
|
||||
),
|
||||
EventFiringComponent.create(
|
||||
id="custom-stop-propagation",
|
||||
on_click=EventActionState.on_click( # type: ignore
|
||||
"custom-stop-propagation"
|
||||
).stop_propagation,
|
||||
),
|
||||
EventFiringComponent.create(
|
||||
id="custom-prevent-default",
|
||||
on_click=EventActionState.on_click( # type: ignore
|
||||
"custom-prevent-default"
|
||||
).prevent_default,
|
||||
),
|
||||
rx.list(
|
||||
rx.foreach(
|
||||
EventActionState.order, # type: ignore
|
||||
@ -202,6 +233,14 @@ def poll_for_order(
|
||||
("link-prevent-default", ["on_click:link_prevent_default", "on_click:outer"]),
|
||||
("link-prevent-default-only", ["on_click:outer"]),
|
||||
("link-stop-propagation-prevent-default", ["on_click:link_both"]),
|
||||
(
|
||||
"custom-stop-propagation",
|
||||
["on_click:custom-stop-propagation", "on_click:outer"],
|
||||
),
|
||||
(
|
||||
"custom-prevent-default",
|
||||
["on_click:custom-prevent-default", "on_click:outer"],
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("token")
|
||||
@ -226,6 +265,9 @@ async def test_event_actions(
|
||||
prev_url = driver.current_url
|
||||
|
||||
el.click()
|
||||
if "on_click:outer" not in exp_order:
|
||||
# really make sure the outer event is not fired
|
||||
await asyncio.sleep(0.5)
|
||||
await poll_for_order(exp_order)
|
||||
|
||||
if element_id.startswith("link") and "prevent-default" not in element_id:
|
||||
|
@ -488,10 +488,10 @@ export const useEventLoop = (
|
||||
|
||||
// Function to add new events to the event queue.
|
||||
const addEvents = (events, _e, event_actions) => {
|
||||
if (event_actions?.preventDefault && _e) {
|
||||
if (event_actions?.preventDefault && _e?.preventDefault) {
|
||||
_e.preventDefault();
|
||||
}
|
||||
if (event_actions?.stopPropagation && _e) {
|
||||
if (event_actions?.stopPropagation && _e?.stopPropagation) {
|
||||
_e.stopPropagation();
|
||||
}
|
||||
queueEvents(events, socket)
|
||||
|
Loading…
Reference in New Issue
Block a user