Bring Drag & Drop to Dash with Dashboard Engine. 💫 Learn how at our next webinar!

Can't get dcc.Loading to act the way I want it to, only works for the first callback

Greetings, I’m struggling to implement a loading icon next to my dropdown input. I can’t seem to be able to make that addition to my dashboard syntax below. I’m trying not to implement another callback in doing so.

body = html.Div(
    [dbc.Jumbotron(
          [
            dbc.Row(dbc.Col(children=[dbc.Spinner(dcc.Dropdown(id="dynamic-dropdown", options=OPTIONS, multi=True, placeholder="Enter your SP500 Symbols"))], lg=6, md=7, sm=12, xs=12),justify='center')
            ], style = {'background-color': '#68d984','margin-bottom':'0px','border-radius':'50px','width':'90%', 'margin-left':'auto','margin-right':'auto'}, fluid=True )
, dbc.Row(dbc.Col([  
                          ],id='graph',lg=9, md=11, sm=12 , xs=12),style={'width':'100%'},justify="center")


       ])



app.layout = html.Div([body])


@app.callback(
    dash.dependencies.Output("dynamic-dropdown", "options"),
    [dash.dependencies.Input("dynamic-dropdown", "search_value")],
    [dash.dependencies.State("dynamic-dropdown", "value")],
)
def update_multi_options(search_value, value):
    if not search_value:
        raise PreventUpdate
    # Make sure that the set values are in the option list, else they will disappear
    # from the shown select list, but still part of the `value`.
    return [
        o for o in OPTIONS if search_value in o["label"] or o["value"] in (value or [])
    ]



@app.callback(
    Output('graph', 'children'),
    [Input('dynamic-dropdown', 'value')],
    [State('graph','children')])

def tickers(symbols, children):
    conn.rollback()
    if symbols == None:
        conn.rollback()
        return []
    elif symbols == []:
        conn.rollback()
        return []
    else:
        stock_info = {}
        d = {} #dates
        p = {} #prices

        sym_ids = tuple([id for id in symbols])

        stock_info = {}
        stock_info = get_dict_resultset("SELECT symbol, date, adj_close FROM api.security_price WHERE security_price.symbol IN %s AND date > (SELECT MAX(date) FROM api.security_price) - interval '1 years' ORDER by date;", [sym_ids])

        stock_data_by_symbol = defaultdict(list)
        for entry in stock_info:
            symbol = entry['symbol']
            stock_data_by_symbol[symbol].append(entry)

        trace = []
        for stock in symbols:
            d[stock] = [rec['date'] for rec in stock_data_by_symbol[stock]] 
            p[stock] = [rec['adj_close'] for rec in stock_data_by_symbol[stock]]
            trace.append(go.Scatter(x=d[stock],
                                 y=p[stock],
                                 mode='lines',
                                 text = d[stock],
                                 opacity=0.7,
                                 name=stock,
                                 textposition='bottom center'))


        traces = [trace]
        data = [val for sublist in traces for val in sublist]
        figure = {'data': data,
                  'layout': go.Layout(
                      colorway=["#9b5de5", '#00f5d4', '#FFD23F', '#f15bb5', '#f71735', '#d08c60'],
                      paper_bgcolor='rgba(0, 0, 0, 0)',
                      plot_bgcolor='rgba(0, 0, 0, 0)',
                      margin={
                        'l': 40, # left margin, in px
                        'r': 10, # right margin, in px
                        't': 16, # top margin, in px
                        'b': 30,}, # bottom margin, in px
                      hovermode='x',
                      legend={"x" : 0, "y" : 1, 'font': {'size': 10}},
                      xaxis={'rangeselector': {'buttons': list([
                                                            {'count': 1, 'label': '1M', 
                                                             'step': 'month', 
                                                             'stepmode': 'backward'},
                                                            {'count': 3, 'label': '3M', 
                                                             'step': 'month', 
                                                             'stepmode': 'backward'},
                                                            {'count': 6, 'label': '6M', 
                                                             'step': 'month',
                                                             'stepmode': 'backward'},
                                                            {'count': 1, 'label': '1Y', 
                                                             'step': 'year',
                                                             'stepmode': 'backward'},
                                                            {'count': 3, 'label': '3Y', 
                                                             'step': 'year',
                                                             'stepmode': 'backward'},
                                                            {'count': 1, 'label': 'YTD', 
                                                             'step': 'year', 
                                                             'stepmode': 'todate'},
                                                            {'step': 'all','label':'MAX'},

                                                            ])},
                         'rangeslider': {'visible': True}, 'type': 'date'},

                      
                      
                  ),


                  }

        
        children = [ 
               dbc.Row(dbc.Col(html.P("As of {}, {}".format(d[stock][-1].strftime('%A'),d[stock][-1].strftime('%d %m-%Y')),style={'font-size':'12px','font_family':'Helvetica Neue', 'margin-top':'10px','color':'#ABABAB'}),style={'position':'relative','float':'right'}, width={"offset": 3}), justify='end'),
               html.Div(style={"width":"100%", "height":'30px'}),
               html.H4('Historical Price Chart:', style={'color':'#474747','margin-left':'30px'}),
               html.P('Interactive graph for end-of-day prices', style={'color':'#A2A2A2','margin-left':'30px'}), 
               dcc.Graph(id='output-graph', figure=figure ,config={'displayModeBar': False}, animate=True,style = {'width': '100%',  'touch-action':'none'}), 
               html.P('* Drag sliders to create your own custom date range', style={'font-size':'12px','color':'#A2A2A2','margin-left':'40px'}),
               html.P('** Double-tap or double-click the main graph to reset axis', style={'font-size':'12px','color':'#A2A2A2','margin-left':'40px'}),
               html.Div(style={"width":"100%", "height":'10px'}),
        ]


        return dcc.Loading(id='graph',children=children,type='graph')

I have only been able to replace my dropdown with a loading icon, but that can get annoying for users, also I wasn’t able to replicate the loading for more than one callback firing.

How can I implement a loading icon or spinner next to a dropdown, appearing only during callback load times?

The way the loading icon works is if an output of a callback is present in the children of the Loading component and the callback is loading, it will show the loading icon/spinner.

The only way for you to show loading icon next to your dropdown is:

	dbc.Jumbotron([
		dbc.Row(
			dbc.Col(
				children=[
					dcc.Dropdown(id="dynamic-dropdown", options=OPTIONS, multi=True, placeholder="Enter your SP500 Symbols")
				],
				lg=6, md=7, sm=12, xs=12
			),
			dbc.Col(
				dbc.Spinner(id='update_me')
			),
			justify='center')
			],
			style={'background-color': '#68d984', 'margin-bottom': '0px', 'border-radius': '50px', 'width': '90%', 'margin-left': 'auto', 'margin-right': 'auto'},
			fluid=True
	),
	dbc.Row(dbc.Col([], id='graph', lg=9, md=11, sm=12, xs=12), style={'width': '100%'}, justify="center")
])

And than in a callback put a Output('update_me", ‘children’) and just return an empty string for this component.

Hope this helps!

Thank you for the kind help :slight_smile: