Problem with class-oriented approach for dynamically reusing templates/components with callbacks

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)