Hi,
I want to have a flexible number of inputs for my Dashboard. Since the Input’s layout is always the same, I created the desired template as a Child Class. This class has a layout property and an associated callback.
Every time the user clicks on the “add an input” button then a new object of the desired layout class is returned and appended to the dashboard.
My problem is:
Whenever I add another input (add a new layout chunk), the callback of the previous object stops working.
in the below example, if an input is added, then despite of changing the source, the names available only correspond to the ones of the first selected source.
here is the code:
# Import
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
#
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config['suppress_callback_exceptions']=True
## #################################### Variables
#Global variable for number of inputs
n=1
#Layout Options /Dropdown 1
sourceOpts=[{'label': 'Source1', 'value': 'S1'},
{'label': 'Source2', 'value': 'S2'}]
#layout options/ Dropdown 2
valOptsA=[{'label': 'Value1', 'value': 'V1'},
{'label': 'Value2', 'value': 'V2'}] #Input values for source 1
valOptsB=[{'label': 'Value3', 'value': 'V3'},
{'label': 'Value4', 'value': 'V4'}] #Input values for source 2
#Function to update global variable
def updt_n():
global n
n=n+1
#################################### Classes Defintion
#Create Parent Class
class Parent:
def __init__(self, app=None):
self.app = app
if self.app is not None and hasattr(self, 'callbacks'):
self.callbacks(self.app)
#Create Child Class with Layout and Callback
class add_input(Parent):
global n
layout = html.Div([
# Source Dropdpwn
html.Div([html.Label('Source:'),
dcc.Dropdown(
id=f'source{n}',
options=sourceOpts
)
],style={'width': '10%', 'display': 'inline-block', 'vertical-align': 'middle'}),
#Ticker Dropdown
html.Div([html.Label('Name:'),
dcc.Dropdown(
id=f'iname{n}'
)
],style={'width': '40%', 'display': 'inline-block', 'vertical-align': 'middle'})
])
def callbacks(self, app):
@app.callback(
Output(f'iname{n}', 'options'),
[Input(f'source{n}', 'value')])
def set_ticker_options(s):
if s=='S1':
return valOptsA
else :
return valOptsB
################################### Layout
temp=add_input(app=app) #create object of class add_input
updt_n()
app.layout = html.Div([temp.layout,
html.Div([
html.Br(), #Blank line
html.Button('Add an Input', id='add-input'),
html.Br(), #Blank line
html.Div(
id='more-inputs'
)
])
],style={ 'textAlign': 'center'}
)
#Call back for the button add input
@app.callback(
Output('more-inputs', 'children'),
[Input('add-input', 'n_clicks')],
[dash.dependencies.State('more-inputs', 'children')]
)
def addTicker_button(n_clicks, child):
updt_n() #update global variable
#temp=add_ticker_input(app=app)
if n_clicks>0:
return html.Div([child,add_input(app=app).layout])
if __name__ == '__main__':
app.run_server(debug=False)