emilhe / dash-extensions

The dash-extensions package is a collection of utility functions, syntax extensions, and Dash components that aim to improve the Dash development experience

Home Page:https://www.dash-extensions.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

EventListener nested properties not working

FRosner opened this issue · comments

Problem

I am trying to use an EventListener to handle clicks on some HTML buttons which are not dash components (because they are inside a data table and data tables don't support dash components 😢 ).

In order to know what dash code to call based on the button clicked, I want to make use of data attributes which contain information about the relevant python code to call and what data to pass (e.g. which row the button was in).

However, it seems that the property extraction code does not give me the full values, but only a subset. The logging debug output shows:

image

While in the callback I only get:

{'srcElement.attributes': {'0': {}, '1': {}, '2': {}, '3': {}, '4': {}}}

Here's the event with the relevant properties I'm interesting in:

CLICK_EVENT = {"event": "click", "props": ["srcElement.attributes"]}

Here's my relevant layout:

EventListener(events=[CLICK_EVENT], logging=True, id=EVENT_LISTENER_ID),
dcc.Store(id=EVENT_LISTENER_STORE_ID, data={}),

Here's the callback:

@dashapp.callback(
    Output(EVENT_LISTENER_STORE_ID, "data"),
    Input(EVENT_LISTENER_ID, "n_events"),
    State(EVENT_LISTENER_ID, "event")
)
def click_event(n_events, event):
    if event is None:
        raise PreventUpdate
    print(event)
    return ""

Alternatively, I tried requesting "srcElement.attributes.data-click.value" directly in the event, which works. Is there a way to get nested props?

It looks like all values are captures (you get 5 values, and the list has length 5), but the content is empty. My first guess would be that the content is not JSON serializeable - could that be the case? Otherwise, could you post a MWE (i.e. a small piece of code that runs and demonstrates the issue), then I can do a bit more debugging.

My first guess would be that the content is not JSON serializeable - could that be the case?

It is a NamedNodeMap, maybe this is the issue indeed. https://stackoverflow.com/questions/25497475/html-attributes-to-json

Otherwise, could you post a MWE (i.e. a small piece of code that runs and demonstrates the issue), then I can do a bit more debugging.

I'm new to the ecosystem, is there some online dash playground I can use?

Alternatively, you can use the example from https://www.dash-extensions.com/components/event_listener

from dash_extensions.enrich import DashProxy, html, Input, Output, State
from dash_extensions import EventListener
from dash.exceptions import PreventUpdate

# JavaScript event(s) that we want to listen to and what properties to collect.
event = {"event": "click", "props": ["srcElement.attributes"]}
# Create small example app
app = DashProxy()
app.layout = html.Div([
    EventListener(
        html.Div("Click here!", className="stuff"),
        events=[event], logging=True, id="el"
    ),
    html.Div(id="log")
])

@app.callback(Output("log", "children"), Input("el", "n_events"), State("el", "event"))
def click_event(n_events, e):
    if e is None:
        raise PreventUpdate()
    return ",".join(f"{prop} is '{e[prop]}' " for prop in event["props"]) + f" (number of clicks is {n_events})"

if __name__ == "__main__":
    app.run_server()

Yes, I believe that is indeed the issue. With the current implementation, you must "drill down" until you reach properties which are (trivially) JSON serializable, which is indeed the case for srcElement.attributes.data-click.value.