Upload analyze and display file, clear div on upload

Short version: on file upload, I want to clear the div, then populate new children into that div. Everything works except the clear part.

I am trying to upload a pdf file and extract certain information from it. All of that works fine, but I have a display issue. When I first load the page, the results div is empty and I populate it. When I upload a subsequent file, the div does not clear until the analysis is completed. I would like to clear the div on file upload and then populate the div when the analysis (which takes several seconds for large files) is complete.

I tried making two callbacks, but that is not allowed because they both use the same inputs and outputs. I suspect that I need one callback to update some hidden element and then use the hidden element as the trigger for a second callback, but then I do not see how to coordinate the upload and the div that I want to modify.

I’ve done this kind of thing before using Flask, but I thought that I would give Dash a try.

Thanks,
Herb

Hi @hroitblat welcome to the forums. Sounds like background callbacks could help in this case if I’m not mistaken:

An example with a image upload (a mashup of this upload example and this example from background callbacks):

import datetime
import diskcache
import time
import dash
from dash import DiskcacheManager, Input, Output, State, html, dcc

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

# Diskcache for non-production apps when developing locally
cache = diskcache.Cache("./cache")
background_callback_manager = DiskcacheManager(cache)

app = dash.Dash(
    __name__,
    background_callback_manager=background_callback_manager,
    external_stylesheets=external_stylesheets
)

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


def parse_contents(contents, filename, date):
    return html.Div([
        html.H5(filename),
        html.H6(datetime.datetime.fromtimestamp(date)),

        # HTML images accept base64 encoded strings in the same format
        # that is supplied by the upload
        html.Img(src=contents),
        html.Hr(),
        html.Div('Raw Content'),
        html.Pre(contents[0:200] + '...', style={
            'whiteSpace': 'pre-wrap',
            'wordBreak': 'break-all'
        })
    ])


@app.callback(
    Output('output-image-upload', 'children'),
    Input('upload-image', 'contents'),
    State('upload-image', 'filename'),
    State('upload-image', 'last_modified'),
    background=True,
    running=[
        (Output('output-image-upload', 'children'), [], []),
    ],
)
def update_output(list_of_contents, list_of_names, list_of_dates):
    time.sleep(3)
    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


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

Thanks, maybe I’m being dense, but more likely I did not describe the problem well enough. The problem is not that I have to wait for the task to finish, it is that I want to clear the div when a new file is dragged into the upload box. When the user submits a new file, I want to clear away the results of the previous file. I then wait for the analysis of the new file to occur (which so far is several seconds so timeout is not an issue), then populate the div with the new results.

I’m new to Dash, so maybe I harbor some serious misunderstandings (I have used flask and D3.js). If I understand correctly, Dash is declarative, not procedural. I am much more used to procedural systems. Also, if I understand correctly, dash only updates the DOM when returning from a callback. Based on this understanding, I should have a callback that is triggered by a change in the dcc.Upload that clears the div (set children = ) and then processes the file. I can see how to do one or the other, but not both from the same event.

What am I misunderstanding? Missing? Thanks.

Hi @hroitblat ,

Background callbacks are not exclusively used to prevent timeout issues.

Did you try running my example? It should show the behaviour you are searching for.