Drill Down Table with Next Button

Hi, I am working on a dash data table where I am making a drill down report. I have been following along with
[https://github.com/amyoshino/Dash_Tutorial_Series/tree/master/Table_Drill_Down]
as an example. It does what I want for the most part, but I am running into an issue of needing to “do nothing” on certain situations.

Here is a sample pseudo-code of what I have:

# load necessary data
my_df = pd.DataFrame(...)

# define an initial dataframe to display
init_df = pd.DataFrame(...)

app.layout = dhc.Div(
    [
        dcc.Store(id='memory'),
        dhc.Div(
            [
                dhc.H4(
                    'EIDs Used Between         '
                    , id='page_title'
                    , style={'display': 'inline-block'}
                ),
                dcc.DatePickerRange(
                    id='date_range_picker'
                    , min_date_allowed=dat(2019, 6, 22).date()
                    , end_date=dat(currentDT.year, currentDT.month, currentDT.day).date()
                    , start_date=dat(currentDT.year, currentDT.month, 1).date()
                    , style={'display': 'inline-block', 'marginLeft': 10}
                )
            ],
            id='date_picker_container'
        ),
        dhc.Div(
            [
                dhc.Button(
                    'Reset Table'
                    , id='reset_table_button'
                    , style={'width': '10%', 'display': 'inline-block'}
                )
            ], style={'display': 'inline-block', 'width': '100%'}
            , id='buttons_container'
        ),
        dhc.Div(
            children=[
                dhc.Div(
                    dt.DataTable(id='table', page_size=20)
                    , id='init_table_div'
                    , hidden=False
                ),
],
            id='table_container',
        )

    ],
    id='page_container'
)

def generate_table(dataframe, out_id='table'):
    return dt.DataTable(
        id=out_id
        , data=dataframe.to_dict('records')
        , columns=[{'id': c, 'name': c} for c in dataframe.columns]
        , page_action='native'
        , page_size=20
    )

@app.callback(
    Output('table_container', 'children'),
    [
        Input('table', 'selected_cells')
        , Input('date_range_picker', 'start_date')
        , Input('date_range_picker', 'end_date')
        , Input('reset_table_button', 'n_clicks_timestamp')
        # , Input('table', 'data')
    ],
    [State('memory', 'data')]
)
def update_init_table_data(sel, start_date, end_date, reset_button, current_table):
    if start_date is not None:
        start_date = dat.strptime(start_date, '%Y-%m-%d').date()

    if end_date is not None:
        end_date = dat.strptime(end_date, '%Y-%m-%d').date()

    # if we have nothing in the current table, then fill the table with the initial df
    if not current_table:
        return generate_table(init_df, 'table')

    if not current_table['data']:
        # print('Table is none')
        return generate_table(init_df, 'table')
    
    if reset_button is None:
        reset_button = 0
    stamp = str(time.time())[:10]
    if stamp == str(reset_button)[:10]:
        return generate_table(init_df, 'table')

    # put current table keys into a list
    curr_keys = [*current_table['data'][0].keys()]
    # set the unique column name
    unq_key = curr_keys[2]

    res = my_df.copy()
    # do some initial filtering that is done for all tables based on date
    res = res[res['Date'] >= start_date]
    res = res[res['Date'] <= end_date]

    # if there is a selection, handle that case:
    if sel:
        print('in sel')
        row_num = sel[0]['row']
        col_id = sel[0]['column_id']

        if unq_key == 'SomeColumn':
            if col_id == 'ApplicationName':
                # do some stuff 
                return generate_table(res, 'table')
            if col_id == 'UserName':
                # do some stuff
                return generate_table(res, 'table')
    if unq_key == 'SomeColumn':
        # in top level and need to do something different for filtering dates
        # do stuff based on being here
        res = ...
    if unq_key == 'UserName':
        # do different things based on being here
        res = ...
    if unq_key == 'UsedApp':
        # do other things based on being here
        res = ...

    return generate_table(res, 'table')


if __name__ == '__main__':
    app.run_server(debug=True)

Ok, so in the above code, we have a call back that takes a date range picker, an active cell, and a reset button as the inputs. The output is the div container of the dashtable.

On every if statement in the update_table() function call, I return a generate_table() command so that we can update the table on screen with what the user does.

The problem is that when the data has too many rows, we automatically get the “Previous” and “Next” buttons so that the data becomes paginated. So, when the user selects the “Next” button on the table, it registers as a selection in the callback and triggers the callback. Which returns a table of the current data that was displayed prior to the selection of the "Next"button. Essentially, the next button triggers this callback and does not allow it to actually move to the next page.

What is the best way to handle this using Dash? If you want interactivity with the table but also the ability to see the next page, how do you do that?

Thanks for any help!