Do not stop prop is there is no prop to stop ()

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:
Masen Furer 2023-11-02 10:21:41 -07:00 committed by GitHub
parent 6e71393ed5
commit bf20a530df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 6 deletions
integration
reflex/.templates/web/utils

View File

@ -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:

View File

@ -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)