Send "fake" event from client-side js to server

I used a hack to “solve” the problem. The approach is as follows:

  1. Create an invisible react Input field (known to dash)
  2. Use the normal @app.callback, referencing the ID of the invisible field
  3. Add javascript function to dispatch synthetic react event using the Input field
  4. From within html code can call the javascript function with a payload

Here is the javascript (which should be put in assets dir):

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


/**
 * Send synthetic react event to application (from client)
 * - detailed here: https://stackoverflow.com/questions/23892547/what-is-the-best-way-to-trigger-onchange-event-in-react-js
 *
 * @param payload payload as string
 */
function sendEventToApp(payload) {
    var rendezvous = document.getElementById("ExternalEvent");
    var newvalue = payload + ":" + __rendezvous_count++;

    __rendezvouz_setter.call(rendezvous, newvalue);

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

Here is a simple contrived test:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import dash_dangerously_set_inner_html

app = dash.Dash(__name__, external_stylesheets = [dbc.themes.UNITED])


def ExternalEvents():
    return dbc.Input(type='text', id='ExternalEvent', placeholder='', style={'visibility': 'hidden'})

def HTML(html):
    return dash_dangerously_set_inner_html.DangerouslySetInnerHTML(html)

@app.callback(Output('target', 'children'), [Input('ExternalEvent', 'value')])
def update_input(value):
    return "Click Me" if value is None else value

app.layout = dbc.Container([
        html.H2("Click Me", id='target'),
        html.Div([
            HTML("""<button onclick='sendEventToApp("button1")' class="btn">test</button>""")
        ]),
        ExternalEvents(),
    ])

app.run_server()
1 Like