Black Lives Matter. Please consider donating to Black Girls Code today.
Learn how to use COVID-19 data in open source Dash apps. Register for the Sept 23rd webinar with IQT!

Get at the value of an arbitrary Input without being reactive to it

I’d like to let the user enter various fields, but not react to them until a button is clicked. How would one accomplish this? For instance:

@app.callback(
     Output('lookups', 'children'),
     events=[Event('run', 'click')])
def lookups():
    # do stuff based on Input('foo', 'value')
    return stuff

Does that make sense? I’m doing an api call with the input (text box) contents. If I make the callback take Input('foo', 'value') and then pass foo to the function, it’s calling the api with each changed character, which fails because the value isn’t complete.

My thought was to wait until a button was clicked. This would signal the user was done typing, and we wouldn’t run into this issue. I do the call with the contents of foo, though, so I don’t want to react to it, but I do need to get at the contents.

Makes sense! Check out https://plot.ly/dash/state for some examples of how to do this.

Well garsh. That’s just perfectly what I wanted. Thanks!

Sorry if it’s me, but I don’t think I ever would have thought of “dash state” as what to search for. I was trying things like “get Input value dash without reacting” or “access Input value dash” and similar… anyway to make this feature more findable? Maybe I should have just been more thorough in reading documentation.

Anyway, thanks a bunch. Super psyched this is so straightforward!

Ran into a snag. I’m dynamically generating a number of fields like so:

## function to generate input widgets
## in_1 is a slider from 1-4, initialized to 1
## in_2 is a div placeholder for on-the-fly generated text fields
## run is a button
def generate_inputs():

    in_1 = [html.Label(html.Strong('select number')),
           dcc.Slider(id='num', min=1, max=4, value=1,
                      marks={i: i for i in range(5)})]
    
    in_2 = [html.Label(html.Strong('text inputs')),
             html.Div(id='ins')]

    run = [html.Label(html.Strong('ready?')),
           html.Button('run!', id='run', n_clicks=0)]

    input_list = [in_1, in_2, run]
    widgets = list()    
    for sublist in input_list:
        sublist.append(html.H1(''))
        for item in sublist:
            widgets.append(item)

    return widgets

## generate_input and an empty ghost div where I can send results
app.layout = html.Div([
    html.H2('app'),
    html.Div(generate_inputs(),
             style={'float': 'left', 'width': '20%', 'padding': '0 0 50px 0'}),
    html.Div(id='lookups',
              style={'float': 'right', 'width': '75%'})
    ])

## when the number of the slider changes, run this
## return back the number of dcc.Inputs matching the desired
## number, each with an id of 'i'
@app.callback(
    Output('in_2', 'children'),
    [Input('in_1', 'value')])
def ins_generate(n):
    boxes = [html.Div(
        dcc.Input(id=str(i),
                  placeholder='a thing', value='thing1',
                  size=40, type='text')) for i in range(n)]
    return boxes

## when the button is clicked access our on-the-fly field, which should get the name '0' `str(i)`
@app.callback(
     Output('lookups', 'children'),
    [Input('run', 'n_clicks')],
    [State('0', 'value')])
def lookups(run_clicks, a0):
    print(a0)

I get “error loading dependencies” when I take this route. I think it has to do with figuring out what the field id is for my variable number of text entries. Sorry if this is a completely separate issue about how I’m trying to do a dynamic number of inputs.

A little more troubleshooting, which has unfortunately increased my confusion! I went about it this way:

  • since I define my slider with an initial value=1, I know that upon load I will have one text box
  • instead of making the id str(i), I’ll just hardcode it as 'a'
  • I’ll then try to access this as an Input since I know it should be there

For reference, here is a gist with my test. Starting callback:

@app.callback(
     Output('lookups', 'children'),
    [Input('run', 'n_clicks')],
    [State('a', 'value')])
def create_lookups(n_clicks, val):
    print(val)

I expected that to react to the click of a button (n_clicks), and print the value contained in the single text box, a. Instead, I get the error loading dependencies message. Then I modified only my clicks callback like so:

@app.callback(
     Output('lookups', 'children'),
    #[Input('run', 'n_clicks')],
    [Input('a', 'value')])
def create_lookups(val):
    print(val)

It works fine with this as an input. So, this confirms the input id exists. Granted, it’s not dynamic and only covers the initial state of one field, but that shouldn’t be the issue… With that working, I tried to use both as inputs:

@app.callback(
     Output('lookups', 'children'),
    [Input('run', 'n_clicks'),
     Input('a', 'value')])
def create_lookups(n_clicks, val):
    print(val)

Now I’m back to the dependencies error. If I comment out either Input, it works (removing the appropriate arg to create_lookups(). I’ll get the number of clicks printed out as I click, or the value of the text box as I type or edit. Any insight into what I’m doing wrong?

I realize that this became about dynamic inputs after getting the answer about State(). Should I move this into a new topic? I can’t really test out the State() answer in my app due to the dependencies error I’m getting. Any further suggestions?