Dash "Re-triggerable" callbacks

What is a “re-triggerable” callback?

Prior to Background Callbacks, I previously (and successfully) implemented a “re-triggerable” callback using the modified_timestamp property of a dcc.Store component as a way to “re-trigger” the same callback. This “re-triggerable” callback contained logic for start/continue/end of the retriggered callback ‘chain’. This was a workaround for the gateway timeout for long running processes, and allowed display of progress update.

Now I am now trying to implement a similar mechanism with Clientside Callbacks to improve overall speed/performance of these callbacks. However, although I can trigger this clientside callback manually, it does not appear to retrigger using the same approach as above.

Why do “re-triggerable” callbacks work for regular callbacks but does not seem to “re-trigger” when using clientside callbacks?


Example template code is shown below.


    Output('clientside-load-data-status-store', 'data'),
    Output('clientside-load-data-status-progress-bar', 'value'),
    Output('clientside-load-data-status-progress-bar', 'max'),
    Input("load-data-bt", "n_clicks"),
    Input('clientside-load-data-status-store', 'modified_timestamp'),
    State('clientside-load-data-status-store', 'data'),


window.dash_clientside = Object.assign({}, window.dash_clientside, {

    load_data: {

        getData: async function loadData (n_clicks, status_modified_timestamp, status_data) {

            let ctx = dash_clientside.callback_context
            let triggered_prop_id = ctx.triggered[0]['prop_id']
            let n_clicks_id = Object.keys(ctx.inputs)[0]

            if (status_data['curr_page'] == 0 && status_data['total_pages'] == 0  && triggered_prop_id == n_clicks_id) {
                // Start callback chain ...
                status_data['curr_page'] = 1
                // Get total pages from initial API call or other means ...
                let total_pages = 3
                status_data['total_pages'] = total_pages
            else if (status_data['curr_page'] <= status_data['total_pages']) {
                // Make API request for current page ...
                status_data['curr_page'] += 1
            else {
                // End callback chain and reset ...
                status_data['curr_page'] = 0
                status_data['total_pages'] = 0

            return [status_data, status_data['curr_page'].toString(), status_data['total_pages'].toString()]

Update: I found a related issue #1774 - [BUG] JavaScript callbacks don’t trigger Python callbacks, but although it was closed, no specific solution was provided.