1

I am quite new to programming and to plotly dash as well. I have some tabs in my dashboard and in each tab i have a text input box (int) and a button that triggers some calculations using the input.

With the following script, when I select the tab, the callback is triggered and the calculation already starts with the empty value in the text, even before I click the button. I do have an if clause to return nothing when the text input box is empty. But that doesn't seem to be working. It directly goes to the final "else" clause. How can i solve this? Thank you!

@app.callback(Output('PRINTOUTPUT', 'children'),
              [Input('create_button', 'n_clicks'),
              Input('selection_tabs', 'value')],
              [State('text-input', 'value')])

def xyz (clicks, selected_tab, textinput):    
    
    changed_id = [p['prop_id'] for p in dash.callback_context.triggered][0] #To determine if n_clicks is changed. 

      
    if 'create_button' not in changed_id:
        return ""

    elif 'create_button' in changed_id:           
        if textinput =="":  #Do nothing if button is clicked and input num is blank.            
            return "No input"
        
        else: 
            #Do some calculations based on the selected tab and input
             return "Successful"

2 Answers 2

2

If there is a problem in your code, it is probably elsewhere than in the part you pasted to the question. I wrote an MWE around the callback you provided and it seems it is working as you intented:

MWE demo1

Improvements for the callback

  • The code below includes a bit improved callback
  • The prop_id attribute of the items in the list dash.callback_context.triggered is of the form component_id.component_property. Therefore, if you want to check whether it was 'create_button' that triggered the callback, you should compare against the part before the dot (or compare to 'create_button.n_clicks' directly).
  • Previously, only the first element in the list dash.callback_context.triggered was checked. You probably want to check against all the elements in the list, although in current version of dash it can only contain properties of single component: "is a length-1 list, unless two properties of a single component update simultaneously, such as a value and a timestamp or event counter." (dash.callback_context.triggered)
  • Increased readability by removing unnecessary nesting of if statements, since the execution of the function will not continue after a return.

Full code

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State

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

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


tab_div = html.Div(
    dcc.Tabs(id='selection_tabs', value='tab-1', children=[
        dcc.Tab(label='Tab one', value='tab-1'),
        dcc.Tab(label='Tab two', value='tab-2'),
]))

app.layout = html.Div(children=[
    html.H1(children='Test app'),
    tab_div,
    dcc.Input(id="text-input", type="text", placeholder=""),
    html.Div(id='PRINTOUTPUT'),
    html.Button('Click me', id='create_button')
])

@app.callback(Output('PRINTOUTPUT', 'children'),
              [Input('create_button', 'n_clicks'),
              Input('selection_tabs', 'value')],
              [State('text-input', 'value')])

def xyz(clicks, selected_tab, textinput):    

    #To determine if n_clicks is changed. 
    changed_ids = [p['prop_id'].split('.')[0] for p in dash.callback_context.triggered]
    button_pressed = 'create_button' in changed_ids

    if not button_pressed:
        return ""

    if textinput == "":  #Do nothing if button is clicked and input num is blank.            
        return "No input"
    
    #Do some calculations based on the selected tab and input
    return "Successful"

if __name__ == '__main__':
    app.run_server(debug=True)
Sign up to request clarification or add additional context in comments.

Comments

0

Assuming that you are using dcc.Input component for your text input, it has an optional parameter value which could be set while defining it. By default, this value is set to python's None. So if you are not setting this parameter's value to empty string "" when defining it, then comparing it to "" in your if clause will result in False, and that is why it always ends up in the else clause.

You just need to check if your textinput is None. Try changing your if clause to if textinput is None: #Do nothing if button is clicked and input num is blank. Or you can also explicitly set the default value of your input box to "" at the place where you are defining it, but that seems a bit counter-intuitive to do.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.