dcc.Upload callbacks with multiple files?

Hello everyone!

When i was doing an interface which dynamically create buttons after an upload of multiple pictures using dcc.Upload, i noticed only the last file treated have the buttons active. The other files have the interface layout correctly adjoined, but none of the callback works.

So i would like to know how to properly handle having multiple pictures uploaded using dcc.Upload so i can interact with all pictures.

Here is my code (simplified) to reproduce the problem (simply upload 2 pictures and try to click on the buttons) :

from dash import Dash, html, dcc
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
import base64
import numpy as np

#CSS
external_stylesheets=[dbc.themes.BOOTSTRAP]

#app
app = Dash(__name__,external_stylesheets=external_stylesheets,suppress_callback_exceptions=True)

#layout
app.layout = html.Div([
        dcc.Upload(
        id='upload-image',
        children=html.Div([
            'Drag and Drop or ',
            html.A('Select Files')
        ]),
        style={
            'width': '70%',
            'height': '60px',
            'justify':'center',
            'text-align':'center',
            'lineHeight': '60px',
            'borderWidth': '1px',
            'borderStyle': 'dashed',
            'borderRadius': '500px',
            'textAlign': 'center',
            'margin': '10px'
        },
        # Allow multiple files to be uploaded
        multiple=True
    ),
    html.Div(id='output-image-upload'),
    ])

#callback upload button
@app.callback(Output('output-image-upload', 'children'),
              Input('upload-image', 'contents'),
              State('upload-image', 'filename'),
              State('upload-image', 'last_modified'))
def update_output(list_of_contents, list_of_names, list_of_dates):
    if list_of_contents is not None:
        children = [
            parse_contents(c, n, d) for c, n, d in
            zip(list_of_contents, list_of_names, list_of_dates)]
        return children 

def parse_contents(contents,unused,unused2):
    content_type, content_string = contents.split(",")
    decoded = base64.b64decode(content_string)
    jpg_as_np = np.frombuffer(decoded, dtype=np.uint8)

    import random
    result = random.randrange(1000)

    return html.Div([
        dcc.Store(id='store-picture',data=result),
        html.Br(),
        dbc.Row([
            dbc.Col(
                html.Img(
                    src=contents,
                    style={
                        'margin-left':'auto',
                        'margin-right':'0px',
                        'width':'40%',
                        'padding-left':'20px'}),
            ),
            dbc.Col(
                html.Div(result,
                style={
                    'font-size':'40px',
                    'padding-top':'10px',
                    'font-weight':'bold',
                    'font-family':'courier',
                }
                )
            ),
            dbc.Col([
                dbc.Row(html.Div('Is the prediction correct?')),
                dbc.Row([
                    dbc.Col(
                        html.Button('Yes',id='button-pred-yes',n_clicks=0)
                    ),
                    dbc.Col(
                        html.Button('No',id='button-pred-no',n_clicks=0)
                    )
                ]),
                dbc.Row(
                    html.Div(id='div-prediction-result')
                )
            ])
        ])
    ])

@app.callback(
    Output('div-prediction-result','children'),
    [Input('button-pred-yes','n_clicks'),Input('button-pred-no','n_clicks')],
    [State('store-picture','data')]
)
def confirm_prediction(bpy,bpn,data):
    prediction = data
    if bpy:
        return prediction
    elif bpn:
        return prediction

#--------- LAUNCHER ------------

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

Hi @arkantos welcome to the forums.

If you dynamically create components, you should take a look into pattern matching callbacks