✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
🐇 Announcing Dash VTK for 3d simulation graphics. Check out the March webinar.

Dash callback with dynamic inputs

Hello! I’m trying to create a dash application that is sort of dynamic. Essentially I have a json object in a redis db that specifies certain configuration options, and I want the page to populate itself off of these options. so say for instance I have this configuration:
{‘Systems:D’: {‘Dev_Station’: ‘none’, ‘Prototype’: {‘Unit:D’: {‘Unit1’: ‘none’, ‘Unit2’: ‘none’}}}}
The keys that have “:D” in them indicate to the app that these fields will create dropdowns with the options of the dropdown being the keys in the inner dictionary. So for instance, the Systems dropdown will be populated automatically, with the options of Dev_Station or Prototype, if the user selects former, then nothing new appears, if the user selects the latter then I want the Unit Dropdown to appear with the options of Unit1 and Unit2.

Now I have this class. with a function that reads that json configuration object and creates both a dictionary of dropdown objects and a list of input objects like so.

class DynamicDashComponents:

    def __init__(self):
        self.dropdowns = dict()
        self.inputs = list()
    
    def create_components(self, config_options):
        keys = config_options.keys()
        for key in keys:
            split_key = key.split(':')
            if config_options[key] == 'none':
                pass
            elif len(split_key) > 1 and split_key[1] == 'D':
                self.dropdowns.update({key: dcc.Dropdown(
                                                    id=key,
                                                    options=[{'label':i, 'value': i} 
                                                    for i in config_options[key].keys()])})
                self.inputs.append(Input(key, 'value'))
            
                self.create_components(config_options[key])
            else:
                self.create_components(config_options[key])

If I print the inputs and dropdowns properties of an instance of this object after feeding it the configuration options above I get the result I want.


Now my plan is to have a callback that looks at the dash callback context and see which dropdown value changed and again, use the json config options to determine which dropdowns if any need to be put on the page. However, I’m not sure how to create this callback. right now I have this:

@app.callback(
    output=Output('dropdown-container', 'children'),
    inputs=dynamic_components.inputs,
    state=[State('dropdown-container', 'children')])
def update_dropdown_containter(*inputs, current_component_list):
    ctx = dash.callback_context
    print(ctx.triggered)
    return current_component_list

I wrote this function just to I can see how the dash.callback_context object looks so I can work with it.

But this callback never gets called. However I know that dash sees my input list because if open the debugger tree thing I see this:
debug_tree

It sees those two dropdown menus and know they have a callback that affects the dropdown container div. But the callback context never gets prints when I select one of the options from the Systems:D dropdown.

Anyone know why this callback won’t be called? Also please let me know if I need to provide anymore code or explanation!

Thank you for reading and have a wonderful day!

I found out why the callback wasn’t firing. It was because the dropdown components I was making weren’t anywhere in the app layout. So suppressed callback expressions were being called and I didn’t know it. I’ve sinced fixed this by just putting the dropdowns in a hidden div.