plotly / dash

Data Apps & Dashboards for Python. No JavaScript Required.
https://plotly.com/dash
MIT License
21.35k stars 2.06k forks source link

Add support for external events #1552

Open tr8dr opened 3 years ago

tr8dr commented 3 years ago

There are situations where may want to send events into dash from a part of the DOM not managed / generated by Dash. For example, DHTML may be generated by a backend and inserted into the DOM shared by Dash. If such content has events, would like to propagate specific events to Dash (and through react's event mechanism).

I have found a way to "hack" this in, but requesting a "proper" implementation. The hack is as follows:

  1. creating a hidden dash entity
  2. adding javascript to send an event to this hidden entity and trigger react
  3. listening on the value of this hidden Dash / DOM entity

The usage is as follows:

def create(...):
    """
    Create the dash app layout
    """
    return dbc.Container([
        <dash layout structure>
        ...
        # hidden element to receive external events inserted into dash DOM
        ExternalEventRendezvous()])

@app.callback(Output(...), [ExternalInput(), ...])
def dosomething(event):
    # event contains the text of the payload sent by the external event
    ...

In the external code, events are sent using the DOM onEvent triggers:

<button class="btn btn-sm" onclick='sendEvent("my-payload")'">click me</button>

Clicking this externally provided button would call the sendEvent() javascript and cause the hidden element to take on the value of the payload and trigger the react event.

The proposal would be to do away with the requirement for the hidden ExternalEventRendezvous() element (which is an Input element).

Here is the supporting javascript function:

var __redendezvous_count = 0;
var __rendezvouz_setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;

/**
 * Send synthetic event to application (from client)
 *
 * @param payload payload as string
 */
function sendEvent(payload) {
    var rendezvous = document.getElementById("ExternalEvent");
    var newvalue = payload + ":" + __redendezvous_count++;

    __rendezvouz_setter.call(rendezvous, newvalue);

    var ev = new Event('input', { bubbles: true });
    rendezvous.dispatchEvent(ev);
}

And here are the python functions:

def ExternalEventRendezvous():
    """
    Add external event rendevous event
    """
    return dbc.Input(type='text', id='ExternalEvent', placeholder='', style={'visibility': 'hidden'})

def ExternalInput():
    """
    External input
    """
    return Input("ExternalEvent", "value")
pikhovkin commented 3 years ago

same issue

RoyTrudell commented 2 years ago

same issue

gewesp commented 2 years ago

I need a way to update a 3D plot in Dash periodically with data generated in the backend Dash app. Not sure if this issue would provide for this, but if it does, it would make Dash infinitely more useful to us.