Automatically move to next input box and remove texts once submitted

Hello! I just joined Plotly Forum and am still learning my way around Dash.

I am building a data entry system with 3 input boxes and a submit button. Entered data compares with a backend database and returns a “PASS/FAIL” alert to the user. Data is entered by using a bar code scanner. Everything is working as intended.

However, to improve the ease of use, I’d like the cursor to move to the next input box as soon as the current box is filled. I’d also like the page to automatically submit and clear all boxes as soon as the last box is filled but the alert should stay.

Here is what I have currently. I’m also open to any suggestions on overall improvement of my code. Thanks!

def update_database(star, serial, weight, andon):
    sheet.append([datetime.now(), A, B, C, andon])
    raw.save(r'test.xlsx')


def compare_tol(A, B, C):
    if star is not '':
        compare_group = df_main.loc[star, 'Group']
        if float(C) > float(df_groups.loc[compare_group, 'Upper']) or \
                float(C) < float(df_groups.loc[compare_group, 'Lower']):
            andon = 'FAIL'
        else:
            andon = 'PASS'
    else:
        andon = '...'
    update_database(A, B, C, andon)
    return andon


def which_entry(label):
    layout = html.Div([
        dcc.Input(
            id=label,
            placeholder=f' {label}...',
            type='text',
            value=''
        )
    ], style={'padding': '5px 5px'})
    return layout


app.layout = html.Div([
    html.Div([
        html.Img(src='http://xxx.png',
                 width='250px')
    ]),
    html.Div([
        html.Div([
           html.H3('Scan A'),
        ]),
        which_entry('A'),
        html.Div([
            html.H3('Scan B')
        ]),
        which_entry('B'),
        html.Div([
            html.H3('Enter C')
        ]),
        which_entry('C'),
    ], style={'text-align': 'center'}),
    html.Div([
            dbc.Button('Submit', id='button', color='primary')
    ], style={'text-align': 'center',
              'width': '250px'}),
    html.Div([
        dbc.Alert(id='andon', color='secondary')
    ], style={'text-align': 'center',
              'width': '250px',
              'padding': '5px 5px'})
], style={'width': '250px'})


@app.callback(
    Output('andon', 'children'),
    [
     Input('button', 'n_clicks')
    ],
    [
     State('A', 'value'),
     State('B', 'value'),
     State('C', 'value'),
    ]
)
def output_text(n_clicks, A, B, C):
    return compare_tol(A, B, C)


@app.callback(
    Output('andon', 'color'),
    [
     Input('button', 'n_clicks'),
     Input('andon', 'children')
    ],
)
def andon_color(n_clicks, andon):
    if n_clicks:
        if andon == 'PASS':
            return 'success'
        elif andon == 'FAIL':
            return 'warning'
    else:
        return 'secondary'

When I’ve made applications like this (which was before Dash existed, so it’s cool to think about making them now in Dash :tada:) I set the barcode reader to have a specific suffix - I needed the barcode readers to be usable in a lot of different contexts, so I used something like <f12> and then had some js on the page listening for that keycode and moving the focus to the next input. That’s a pretty simple bit of js, could be just included in your assets if need be. But if you’re only going to be using the barcode reader for this purpose maybe you could just set the suffix to <tab>, which would automatically move to the next field?

Then I think you could make a single callback triggered by the last field losing focus, something like:

@app.callback([
    Output('andon', 'children'),
    Output('andon', 'color'),
    Output('A', 'value'),
    Output('B', 'value'),
    Output('C', 'value')
], [
    Input('C', 'n_blur')
], [
    State('A', 'value'),
    State('B', 'value'),
    State('C', 'value')
])
def output_all(n_blur, A, B, C):
    if not n_blur:
        raise dash.exceptions.PreventUpdate
    andon = compare_tol(A, B, C)
    return andon, andon_color(andon), '', '', ''
1 Like

Hey, I appreciate your response!

I agree with you on programming the tab input on the scanner side. I think the one I am using can pick up commands in the barcode itself too so I will definitely look into that. I thought maybe there was a way through Dash.

And your code worked perfectly, I didn’t know n_blur existed. It is exactly what I am looking for, thank you so much!