Catch when Div innerHTML is updated by Javascript eventListener

Hello there

I have an iframe in my app and have setup some custom Javascript that is an event-listener that throws whatever it finds into the innerHTML of a Div in my app.

I would like to be able to somehow “grab” this data so I can have my app react in certain ways when certain information.

For overviews sake, here is a screenshot of the app:

Here is the javascript:

window.addEventListener("message", receiveMessage, false);

function receiveMessage(e){
    if (e.origin !== "https://zingtree.com") {
        alert ("I did NOT see message comming from Zingtree, I have blocked it...");
    } else {
        document.getElementById("iframe-message").innerHTML += e.data;
    }
}

And here is the python script for the app:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State

app = dash.Dash(__name__)
server = app.server
app.config['suppress_callback_exceptions']=True
app.title = 'RFC Demo'

app.layout = html.Div(
    children=[
        html.Div(id='div-test'),
        html.Div(
            html.Iframe(id='iframe-test',src=f'https://zingtree.com/deploy/tree.php?z=embed&tree_id=TREE-ID',style={'width': '80%', 'height': '500px', 'sandbox': 'True'})
        ),
        html.Div(id='iframe-message')  
    ]
)

if __name__ == '__main__':
    app.run_server(debug=True)

I have tried something simple like adding a callback like:

    Output('show-node', 'children'),
    [Input('iframe-message', 'children')])
def showNode(messageString):
    'do something smart here....'
    return

But it just gives me a None:slightly_frowning_face:

Any help how to somehow get out the information from the eventListener or innerHTML of html.Div(‘iframe-message’) is much appreciated! (Or to tell me if it is even possible…)

Hi @Blaceus, Clientside JavaScript does not communicate with the Python server (and thus the rest of your callbacks) unless you explicitly define a Clientside callback (see an example here).
How I see your issue solved is this: instead of an eventListener, you define a Clientside callback with Input your activation Button and Output("iframe-message", "children"). Then instead of setting the innerHtml in your JavaScript you simply return the text from the iFrame.

Then you can catch the update of the children property of your "iframe-message" div in a regular Python callback.

2 Likes

Thank you @RenaudLN for letting me know about the clientside functionality, I’d missed that somehow.

Can you elaborate what you mean about this, please?:

What is my activation button in your mind, the buttons inside the iframe?

Let me ellaborate on the eventListerner.
I know from the Zingtree software group that if you deploy one of their solutions in an iFrame, it will send a message about which decission tree and node the user is currently at. So if I can get a clientside callback to send back the eventListener text to the server, I could easily parse this text using Python and let my app react as I wish based on this.

@Blaceus, For some reason I understood from your first message that there was a button that the user needed to click but upon re-reading there is no such thing.

You cannot per se use a javascript listeners (unless there’s a component I don’t know about that does this). What you could do is set up an Interval component that triggers a Clientside callback periodically in which you check the content of your Iframe and return the text you need for your app.