Hi All,
I have built a react app, with 2 iframes, each iframe host a dash app.
Each dash app have dropdowns or filters.
I want to synchronize the dropdowns across the dash apps using postMessage API of the react.
Till now i am able to record the filter value of the originating dash app(dash app 1), send the message to react via postMessage and broadcast to all the other dash apps. Lastly the other dash apps are receiving the message, extracting the filter value and tries to change the filter of the dash app(dash app 2).
But only the inner Html seems to change not the filter UI of the dash.
This is the react App.js
import React, { useEffect } from 'react';
function App() {
useEffect(() => {
const handleMessage = (event) => {
const allowedOrigins = ['http://localhost:8050', 'http://localhost:8051'];
if (!allowedOrigins.includes(event.origin)) return;
try {
const data = event.data;
if (data.type === 'filterChange') {
// Broadcast to other iframes except the sender
const iframes = document.getElementsByTagName('iframe');
Array.from(iframes).forEach(iframe => {
if (iframe.contentWindow !== event.source) {
iframe.contentWindow.postMessage({
type: 'filterChange',
value: data.value,
origin: event.origin
}, '*');
}
});
}
} catch (error) {
console.error('Error processing message:', error);
}
};
window.addEventListener('message', handleMessage);
return () => window.removeEventListener('message', handleMessage);
}, []);
return (
<div>
<h1>React App</h1>
<div style={{ display: 'flex' }}>
<iframe
src="http://localhost:8050"
width="600"
height="400"
title="Dash App 1"
style={{ marginRight: '20px' }}
></iframe>
<iframe
src="http://localhost:8051"
width="600"
height="400"
title="Dash App 2"
></iframe>
</div>
</div>
);
}
export default App;
Same code for dash app 1 and dash app 2, with different ports at last line
from dash import Dash, dcc, html
from dash.dependencies import Input, Output, ClientsideFunction
app = Dash(__name__)
# Define the layout with the dropdown and message area
app.layout = html.Div([
html.Div(id='heading', children='Dash App 1'), # Add this to distinguish the apps
html.Div(id='out-message', children=''), # Placeholder for the out-message
dcc.Dropdown(
id='filter-dropdown',
options=[
{'label': 'Option 1', 'value': 'Option 1'},
{'label': 'Option 2', 'value': 'Option 2'},
{'label': 'Option 3', 'value': 'Option 3'}
],
value='Option 1' # Set initial value
)
])
# Clientside callback to sync the dropdown value based on messages from React app
app.clientside_callback(
ClientsideFunction(
namespace='clientside',
function_name='syncFilters'
),
Output('filter-dropdown', 'value'),
Input('filter-dropdown', 'value')
)
if __name__ == '__main__':
app.run_server(debug=True, port=8050) # Change the port here for Dash App 2
Clientside.js function
Put this code under assets/clientside.js
window.dash_clientside = Object.assign({}, window.dash_clientside, {
clientside: {
syncFilters: function(value) {
// Send message to parent (React) when dropdown changes
if (value) {
window.parent.postMessage({
type: 'filterChange',
value: value
}, '*');
}
// Listen for messages from parent (React app)
window.addEventListener('message', function(event) {
// Ensure the message is coming from a valid source (React app)
if (event.origin !== 'http://localhost:3000') return; // React app's origin
if (event.data.type === 'filterChange') {
// Update the dropdown value in Dash
const dropdown = document.getElementById('filter-dropdown');
const outMessage = document.getElementById('out-message');
// Update the out-message div
outMessage.innerHTML = event.data.value;
// Now, update the dropdown value and trigger a change event
dropdown.value = event.data.value;
// Return the updated value for Dash callback
return event.data.value;
}
return window.dash_clientside.no_update;
});
// Return the current dropdown value to handle user input changes
return value;
}
}
});
the text seems to change according to the selected filter in other dash app, but i dont understand why the filter value is not changing.
Please help me. This is important.
This is a great community, it has helped me a lot.
Thank you.