`EventListener` only triggers once unless `props` change
TimChild opened this issue · comments
Hi @emilhe, first of all, thanks for the excellent package you have created! Lots of great work in here!!
It's possible this behaviour is actually correct/intentional, but it was not obvious to me at first, and maybe would benefit from a note or warning in the docs.
When listening for the change
event, I noticed that even though the console logs the change even (using logging=True
in your EventListener
), the callback associated with it only fires once unless the props
value also changes.
Here's a minimal example that demonstrates the issue.
app.layout = html.Div(
[
html.Div("With prop that changes"),
EventListener(
id="event-listener-with-prop",
events=[
{
"event": "change",
"props": ["srcElement.value"],
}
],
logging=True,
children=[
dcc.Input(id="input-with-prop", type="text"),
],
),
html.Div(id="output-with-prop"),
html.Hr(),
html.Div("Without prop that changes"),
EventListener(
id="event-listener-no-prop",
events=[
{
"event": "change",
"props": [],
}
],
logging=True,
children=[
dcc.Input(id="input-no-prop", type="text"),
],
),
html.Div(id="output-no-prop"),
]
)
with_prop_counts = 0
@app.callback(
Output("output-with-prop", "children"), Input("event-listener-with-prop", "event"), prevent_initial_call=True
)
def update_output(event):
global with_prop_counts
with_prop_counts += 1
return f"Num times triggered: {with_prop_counts}\nEvent triggered with: {event}"
without_prop_counts = 0
@app.callback(Output("output-no-prop", "children"), Input("event-listener-no-prop", "event"), prevent_initial_call=True)
def update_output(event):
global without_prop_counts
without_prop_counts += 1
return f"Num times triggered: {without_prop_counts}\nEvent triggered with: {event}"
if __name__ == "__main__":
app.run(debug=True)
Both trigger once when typing text then changing focus away from the text box.
But, if I change the text in both boxes and then change focus away again, only the one with a prop that changes updates.
Possible that this relates to #282 as I expect that would have similar behaviour since there are no props
specified.
In Dash, callbacks are triggered on property changes, which is why e.g. button clicks are typically signaled by incrementing a counter. Hence, what you are seeing is indeed expected behavior.
Thanks for the speedy response! Ok, well that does make sense, although it still might be worth a little note in the docs.
I was wrongly assuming that the EventListener was directly triggered by the js events and that the event
prop was just a convenient way to get the event details... But, it does of course make more sense that the event
propery is just like any other dash property... Anyway, it wasn't immediately obvious that I would need to add in a prop that I don't necessarily care about to catch the event I was listening for, and I imagine it might catch others out when using it for things like resize
events as in #282.
Anyway, thanks again!
Thanks! I'll keep that in mind 👍 . I don't think that it's related to #282 though.
Docs are now updated. http://localhost:7879/components/event_listener
@emilhe New docs look great! I think you meant to post this link :)
https://www.dash-extensions.com/components/event_listener
Ah, yes, you are correct 😀