Please advise on the usage of ALL, What needs to be improved?

  1. When the “butt del” button is pressed, after the del_output function is executed, I don’t know why the handle_button function starts to be executed.
    action:“butt del” click → del_output() . ||–> handle_button()

  2. action: up_add,down_add click ,butt del click.

Please give me some ideas,thank you all

import dash
from dash import Dash, html, dcc, Input, Output, State, callback, ALL, ctx

app = Dash(__name__, suppress_callback_exceptions=True, )


def get_index_by_id(data: list, id: str):
    """
    :param data:
    :param id:
    :return:
    """

    for i, item in enumerate(data):
        if 'id' in item['props'] and item['props']['id'] == id:
            return i
    return -1


def opt(u):
    return html.Div(
        [
            html.Button('up_add', id={'type': 'up_add', 'index': u}),
            html.Button('down_add', id={'type': 'down_add', 'index': u}),
            html.Button('butt_del', id={'type': 'butt_del', 'index': u}),
            html.Label(u),
        ],
        id=u,
    )


app.layout = html.Div(
    [
        # Read external resources  n =  5
        *[opt(str(i)) for i in range(5)],

        dcc.ConfirmDialog(
            id='confirm-danger',
            message='Danger danger! Are you sure you want to continue?',
        ),
        dcc.Store(id='options_store'),

    ],
    id='options',
    style={'padding': '50px'}
)


@app.callback(
    Output('options', 'children', allow_duplicate=True),  # Output to update: the children of the 'options' div
    Output('confirm-danger', 'displayed', allow_duplicate=True),
    Output('options_store', 'data', allow_duplicate=True),
    [Input({'type': 'up_add', 'index': ALL}, 'n_clicks'),  # Input for up_add buttons
     Input({'type': 'down_add', 'index': ALL}, 'n_clicks'),
     Input({'type': 'butt_del', 'index': ALL}, 'n_clicks'),
     ],  # Input for down_add buttons
    [State('options', 'children')],  # State to access existing children
    prevent_initial_call=True
)
def handle_button(up_add_clicks, down_add_clicks, butt_del_clicks, existing_children):
    ctx_index = ctx.triggered_id.index
    ctx_type = ctx.triggered_id.type

    item = dash.Patch()
    index = get_index_by_id(existing_children, ctx_index)

    if ctx_type == 'up_add':
        item.insert(index=index, item=opt(str(index) + " up_add"))
    elif ctx_type == 'down_add':
        item.insert(index=index + 1, item=opt(str(index) + " down_add"))
    elif ctx_type == 'butt_del':
        # del item[index]
        return dash.no_update, True, dict(index=ctx_index)  # del confirm

    return item, False, dash.no_update


@callback(
    Output('options', 'children', allow_duplicate=True),
    Input('confirm-danger', 'submit_n_clicks'),
    State('options', 'children'),
    State('options_store', 'data'),
    prevent_initial_call=True
)
def del_output(submit_n_clicks, existing_children, options_store_data: dict):
    if submit_n_clicks:
        ctx_index = options_store_data.get("index")
        index = get_index_by_id(data=existing_children, id=ctx_index)
        item = dash.Patch()
        del item[index]
        return item

    return dash.no_update


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

Your ability to structure your problem description needs work🙂.

You can see the problem by running it,

import uuid

import dash
from dash import Dash, html, dcc, Input, Output, State, callback, ALL, ctx

app = Dash(__name__, suppress_callback_exceptions=True, )


def get_index_by_id(data: list, id: str):
    """
    :param data:
    :param id:
    :return:
    """

    for i, item in enumerate(data):
        if 'id' in item['props'] and item['props']['id'] == id:
            return i
    return -1


def opt(u):
    return html.Div(
        [
            html.Button('up_add', id={'type': 'up_add', 'index': u}),
            html.Button('down_add', id={'type': 'down_add', 'index': u}),
            html.Button('butt_del', id={'type': 'butt_del', 'index': u}),
            html.Label(u),
        ],
        id=u,
    )


app.layout = html.Div(
    [
        html.Div(
            [opt(str(i)) for i in range(5)],
            id='opt_items'
        ),

        dcc.ConfirmDialog(
            id='confirm-danger',
            message='Danger danger! Are you sure you want to continue?',
        ),
        dcc.Store(id='item_store'),

    ],
    id='options',
    style={'padding': '50px'}
)


@app.callback(
    Output('opt_items', 'children', allow_duplicate=True),  # Output to update: the children of the 'options' div
    Output('confirm-danger', 'displayed', allow_duplicate=True),
    Output('item_store', 'data', allow_duplicate=True),
    [Input({'type': 'up_add', 'index': ALL}, 'n_clicks'),  # Input for up_add buttons
     Input({'type': 'down_add', 'index': ALL}, 'n_clicks'),  # Input for down_add buttons
     Input({'type': 'butt_del', 'index': ALL}, 'n_clicks'),
     ],
    [State('opt_items', 'children'),
     State('item_store', 'data'),
     ],  # State to access existing children
    prevent_initial_call=True
)
def handle_button(up_add_clicks, down_add_clicks, butt_del_clicks, opt_items_children, options_store_data: dict):
    if (options_store_data is not None) and "tag" in options_store_data and options_store_data['tag'] == 2:
        return dash.no_update, False, {}

    ctx_index = ctx.triggered_id.index
    ctx_type = ctx.triggered_id.type

    item = dash.Patch()
    index = get_index_by_id(opt_items_children, ctx_index)

    if ctx_type == 'up_add':
        item.insert(index=index, item=opt(str(uuid.uuid4()) + " up"))
    elif ctx_type == 'down_add':
        item.insert(index=index + 1, item=opt(str(uuid.uuid4()) + " down"))
    elif ctx_type == 'butt_del':
        # del item[index]
        return dash.no_update, True, dict(index=ctx_index, tag=1)  # del confirm

    return item, False, dash.no_update


@callback(
    Output('opt_items', 'children', allow_duplicate=True),
    Output('item_store', 'data', allow_duplicate=True),
    Input('confirm-danger', 'submit_n_clicks'),
    State('opt_items', 'children'),
    State('item_store', 'data'),
    prevent_initial_call=True
)
def del_output(submit_n_clicks, opt_items_children, options_store_data: dict):
    if submit_n_clicks:
        ctx_index = options_store_data.get("index")
        index = get_index_by_id(data=opt_items_children, id=ctx_index)
        item = dash.Patch()
        del item[index]
        return item, dict(index=ctx_index, tag=2)

    return dash.no_update, dict(index=None, tag=1)


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