Need urgent help - app.callback function doesn't get triggered at all. What should I do?

from Stackoverflow: triggers - Python plotly-dash @app.callback()-function isn't triggered. What should I do? - Stack Overflow (I’ve gotten no answer to this)

I am programming a multi-page app with Python dash-plotly. My app.py-program has the following layout structure:

app = dash.Dash(__name__)  

url_bar_and_content_div = html.Div([
    dcc.Location(id='url', refresh=True),
    html.Div(id='page-content'),
    dcc.Store(id='store1', storage_type='memory'),
    dcc.Store(id='store2', storage_type='memory')
])

layout_page1 = html.Div([ ... ])
 
layout_page2 = html.Div([ 
    ... 
    
    html.Div([
                    html.Button(id='submit-button',
                                        n_clicks=0,
                                        children='Submit',
                                        style={'background-color': '#84cc32', 'color': 'white'}
                    )], className="assay__element"),
    ...
  
    dcc.Store(id='page2-storage-1', storage_type='memory'),
    dcc.Store(id='page2-storage-2', storage_type='memory'),


])     
# so 2 pages in total

# index layout
app.layout = url_bar_and_content_div

# "complete" layout
app.validation_layout = html.Div([
    url_bar_and_content_div,
    layout_page1,
    layout_page2
])

# amongst callback-functions and hidden Divs in layout_pages etc.

The structure basically follows the 3rd code example of the doc page URL Routing and Multiple Apps | Dash for Python Documentation | Plotly 1-to-1!

So at the moment I am trying, amongst other things, to transfer the two stored datas (‘page2-storage-1’ and ‘page2-storage-2’) of layout_page2 to url_bar_and_content_div (‘store1’ and ‘store2’), and here is where I’m failing:

@app.callback([Output('store1', 'data'),       # simplified! (unnecessary lines discarded)
               Output('store2', 'data'),
               ...,
               Output('submit-button', 'n_clicks')],    # the "Submit"-button of page 2
               Input('submit-button', 'n_clicks'),      # it gets triggered by a click
              [State('page2-storage-1', 'data'),
               State('page2-storage-2', 'data')])
def submit_to_page1(n, stored_1, stored_2):
    if n>0:
        if stored_data is not None:
            #print(stored_1)
            #print(stored_2)
            return stored_1, stored_2, ...
        return dash.no_update, dash.no_update, ...
    return dash.no_update, dash.no_update, ...

@app.callback(Output(...),
             [Input('store1', 'data'),
              Input('store2', 'data')],
              State(...),
              prevent_initial_call=False)
def to_page2(stored_1, stored_2, ...):
    #print(stored_1)
    #print(stored_2)
    print("Hey")
    do stuff
    return ...

The FIRST callback works, it is triggered by a click on an html-Button() on page 2, and as a reaction sends/returns the two saved datas (‘page2-storage-1’ and ‘page2-storage-2’) to the save places of the index layout (‘store1’ and ‘store2’). I have of course tested if the callback worked, as is seen in the code, by having added those two command lines print(stored1&2) to see if the data were really received (It was!).

The SECOND callback is NOT working, and I don’t know why. In the parameters of to_page1, I first wrote prevent_initial_call=False, so that the callback would be executed in the initial call, and I also printed the storage places of the index layout (to which the datas in the first callback are returned, those outputs) and at the start they were indeed both empty!
So that must mean that this callback should be triggered because its two inputs were empty before but then received the data from the former callback! So why doesn’t it get triggered then??
When I disable the initial call prevention, the callback function never gets triggered, it never executes, I know because the printed text “Hey” never appears on the console. So why is it? Did the dcc.Stores of url_bar…div get filled at some point time, or does the returned data really Not reach the two save slots? Or is it some issue that I’m sending two input datas at the same time or something like that, or even some syntax issue??

How do I know?? How can I find out what the reason is that the latter callback does not get triggered?? Are there some attributes, or commands etc. I could use that could help me in a way?
There is another callback that isn’t getting triggered too, but it’s more or less the same situation like this one here, so I could fix them both.

I’d be very thankful if someone here responds to my issue, I’d appreciate the help! Thanks in advance!

Hi @Stribor

From what you have posted here, it’s hard to understand exactly what you are trying to do. But generally, triggering a callback based on changes to the data in dcc.Store should work, but there are many reason why it may not.

Here are some typical bugs that cause a callback not to fire - especially in a multi-page app:

  1. Id’s are not unique. All ids must be unique in the entire app - not just unique per page of a multi-page app
  2. There is a typo in the id. For example in the layout an id is button-1 and in the callback it’s button_1
  3. All the components in the Outputs, Inputs and States are not in the layout. This can happen if one of the components is dynamically added to the layout from a different callback.
  4. There is an error on the page. Be sure to set debug=True so the dev tools show the errors and/or check the console for error messages.
if __name__ == "__main__":
    app.run_server(debug=True)

To debug, it’s helpful to try to isolate the error in a minimal working example. The first step could be making a single page app based on code you posted. Once that’s working, you could change it to a multi-page app. Then you would know the error is from the multi-page structure rather than the callback logic.

If you post a complete mwe, it will be easier for someone to give more specific guidance.

5 Likes

Hello @AnnMarieW ,

Thank you very much for your response, I have just quickly skimmed over my code and checked the points you wrote, unfortunately I couldn’t find any related errors yet. The reason why I haven’t posted the full code here is that the software/program belongs to the company in which I am currently doing my internship, I am not allowed to display any concrete parts of the code. (I have even changed/generalized all the variables in the post!)

I will discuss this problem with my internship supervisor, who is leading this project, in two days. Maybe we will find a solution to this, I will document it if we really do!

Cheers

Hi again!

So I have set that debug variable to True and have tested how the program would be reacting to this.
And actually right after I executed the app.py, the debugger did give me some error messages on the console:

A nonexistent object was used in an `Input` of a Dash callback. The id of this object is `upload-data` and the property is `contents`. The string ids in the current layout are: [url, page-content, store1, store2, <all components of page 2>]
Attempting to connect a callback Input item to component: "data_table" but no components with that id exist in the layout.
Attempting to connect a callback Input item to component: "a_switch" but no components with that id exist in the layout.
Attempting to connect a callback Output item to component: "data_table2" but no components with that id exist in the layout.

So I will now explain these messages and the mentioned “non-existent” components. All of them are components of page 1 (at the moment of triggering the callbacks we are on page 2).

First, about those last three components, “data_table”, “a_switch”, and “data_table2” :
Well, these components actually do not yet exist, I have put ‘data_table’, ‘data_table2’, ‘a_switch’ in hidden divs to be returned in callbacks of page 2, so they’re dynamic components! They are not initialized until the user would have hit a submit button on page 2 to go to page 1.
Well, to be frank, I don’t know how to deal with this particular issue, I am new with programming plotly-dash stuff, could you maybe just briefly explain to me what I would have to change in the code so that the non-existence of these components would not disturb the program, i.e. not being viewed as a bug?

Now to the very first message. ‘upload-data’ is also another component of page 1, and it already exists, in fact, it’s supposed to exist at the beginning! I don’t understand why it’s not existing for the program? Why was I able to establish a connection between page 2 and the index layout (url_bar_and_content_div), but not at all between the index layout and page 1?? In the beginning when I went from page 1 to page 2 I, was able to communicate between page 1 and the index page, why are the components of page 1 suddenly unknown now??
Is it because the components of a page become “unknown” as soon as some other page is currently displayed on the dashboard and not that page in question?

This is the job of app.validation_layout. It allows you to set valid callbacks in the case that the output components are not yet defined in the initial view. If I understand you correctly, these components will be passed dynamically to page 1 via a callback, so you must write at least a “fake” block with these components to app.validation_layout that you have.

As of your second point, I want to echo what AnnMarieW said about having a reprex. In your original comment, there are many places where page1 and page2 are switched, which makes hard to follow. Besides, your latest error message refers to components that we can’t see on the code, so it is tough to say what is wrong.

That said, apart fixing potential errors from undefined components, one thing you can try is to switch ‘store1’ and ‘store2’ to storage_type='local', as a page reload might be flushing out the data inside them when you navigate between page1 and page2.

2 Likes