✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
⚡️ Concerned about the grid? Kyle Baranko teaches how to predicting peak loads using XGBoost. Register for the August webinar!

Adding a 'Select All' Button to a Multi-Select Dropdown

I wanted to add a button, which selects all the options in my drop-down menu, except I don’t know how to return such a command.

Any help?

A workaround would be adding an ‘All’ option in the dropdown, and somehow making sure that when it is selected, all the other options clear, but it sound like more of a hassle, right?

1 Like

What you need to do here is have the values of your drop down the Output and the options as a State of some other callback, the Input can be some other component such as a checklist. Here is an example:

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

app = dash.Dash()

app.layout = html.Div([

    dcc.Dropdown(id='dropdown', multi=True,
                 options=[{'label': i, 'value': i} for i in range(10)], value=[1]),
    dcc.Checklist(id='select-all',
                  options=[{'label': 'Select All', 'value': 1}], values=[])
])


@app.callback(
    Output('dropdown', 'value'),
    [Input('select-all', 'values')],
    [State('dropdown', 'options'),
     State('dropdown', 'value')])
def test(selected, options, values):
    print(selected)
    if selected[0] == 1:
        return [i['value'] for i in options]
    else:
        return values


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

3 Likes

@mikesmith1611

This really works in order to select all.
But is it possible to undo the tick mark of the select-all Checklist once you start changing some of the items in the Dropdown?

Say I did press the Checklist ‘select-all’, which populates the dropdown with multiple values (let say total 10 values). Now If I make changes to the dropdown, i.e remove one or two values from the multi-select dropdown list. How would I update the state of ‘select-all’ checklist (remove the tick mark)?

When I tried to do what I did below. It shows ‘Error loading dependencies’

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

app = dash.Dash()

app.layout = html.Div([

    dcc.Dropdown(id='dropdown', multi=True,
                 options=[{'label': i, 'value': i} for i in range(10)], value=[1]),
    dcc.Checklist(id='select-all',
                  options=[{'label': 'Select All', 'value': 1}], values=[])
])

@app.callback(
    Output('dropdown', 'value'),
    [Input('select-all', 'values')],
    [State('dropdown', 'options'),
     State('select-all', 'options')])
def test(selected, options_1, options_2):
    if len(selected) > 0:
        return [i['value'] for i in options_1]
    else:
        return []


@app.callback(
    Output('select-all', 'values'),
    [Input('dropdown', 'value')],
    [State('dropdown', 'options')])
def tester(selected, options_1):
    print(selected)
    if len(selected) < len(options_1):
        return []


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

Hi,

Your seeing this error because of a circular dependency between Inputs and Outputs which is not allowed in Dash. You can see this if you hit F12 and go to console (in chrome).

This is a limitation of Dash which I have been stuck on several times.

This is an eleborate workaround! Instead of using the ‘select-all’ values as an output is uses a parent container and alters it’s children. I had to include some PreventUpdate calls to stop an infinite loop!

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, Event, State
from dash.exceptions import PreventUpdate
app = dash.Dash()

app.layout = html.Div([

    dcc.Dropdown(id='dropdown', multi=True,
                 options=[{'label': i, 'value': i} for i in range(10)], value=[1]),
    html.Div([
        dcc.Checklist(id='select-all',
                    options=[{'label': 'Select All', 'value': 1}], values=[])
    ], id='checklist-container')
])

@app.callback(
    Output('dropdown', 'value'),
    [Input('select-all', 'values')],
    [State('dropdown', 'options')])
def test(selected, options):
    if len(selected) > 0:
        return [i['value'] for i in options]
    raise PreventUpdate()


@app.callback(
    Output('checklist-container', 'children'),
    [Input('dropdown', 'value')],
    [State('dropdown', 'options'),
     State('select-all', 'values')])
def tester(selected, options_1, checked):

    if len(selected) < len(options_1) and len(checked) == 0:
        raise PreventUpdate()

    elif len(selected) < len(options_1) and len(checked) == 1:
        return  dcc.Checklist(id='select-all',
                    options=[{'label': 'Select All', 'value': 1}], values=[])

    elif len(selected) == len(options_1) and len(checked) == 1:
        raise PreventUpdate()

    return  dcc.Checklist(id='select-all',
                    options=[{'label': 'Select All', 'value': 1}], values=[1])

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

I’m not sure that this behaviour will ever change in Dash.

2 Likes

This is a great workaround. I was unaware of the PreventUpdate() function. I think this will help me to hack together a pretty good select all, unselect all checklist functionality as of now.

Hello,

I would like to use this workaround with a picklist suggesting some initial default values.

First issue is that the 1st time the page is loaded, the list shows the X items I want to suggest, but the Bar graph doesnt display anything until i pick a X+1th item in the list. I tried to change a bit the logic in the code but without success.

Additionally, I aim to add either a button or another Checklist to reset the list to the default suggestions, but prior to this I have to fix the first issue.

It makes sense because the graph presents the sales of ~50 products, but 10 out of 50 represents 95% of the sales. So, by default, I want to show the sales figures for these 10 products.

Below a code illustrating the current the problem, with the workaround presented above.

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

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

import plotly.graph_objs as go
from dash.exceptions import PreventUpdate

xTime=['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun','Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

listofY=['y1','y2','y3','y4','y5','y6','y7','y8','y9','y10']

Table={
       'y1':[20, 14, 25, 16, 18, 22, 19, 15, 12, 16, 14, 17],
       'y2':[19, 18, 22, 14, 15, 19, 15, 14, 14, 21, 16, 16],
       'y3':[11, 14, 21, 16, 16, 10, 15, 11, 10, 12, 11, 16],
       'y4':[14, 10, 27, 14, 16, 14, 15, 18, 14, 12, 12, 16],
       'y5':[16, 15, 22, 18, 18, 19, 15, 13, 15, 12, 18, 17],
       'y6':[18, 17, 25, 14, 16, 11, 13, 14, 20, 14, 12, 18],
       'y7':[11, 14, 22, 14, 13, 19, 15, 17, 14, 12, 17, 19],
       'y8':[13, 14, 20, 14, 16, 17, 15, 14, 10, 13, 14, 20],
       'y9':[15, 15, 22, 15, 11, 13, 15, 14, 11, 14, 12, 22],
       'y10':[10, 11, 22, 14, 16, 21, 15, 14, 10, 12, 11, 16]
       }

app = dash.Dash()

app.layout = html.Div([
    html.Div([
        dcc.Dropdown(
            id='product-choice',
            options=[{'label': i, 'value': i} for i in listofY], 
            value=['y1', 'y2', 'y5'],
            multi=True
        ),
        html.Div([
            dcc.Checklist(
                id='select-all',
                options=[{'label': 'Select All', 'value': 1}], 
                values=[]
            )
        ], id='checklist-container')
    ]),
    
    html.Div(children=[
        dcc.Graph(
            id='bar-graph-by-model'
        ),
    ]),                
])

# Below the Workaround suggested by mikesmith1611
#@app.callback(
#    Output('product-choice', 'value'),
#    [Input('select-all', 'values')],
#    [State('product-choice', 'options')])
#def test(selectALL, options):
#    if len(selectALL) > 0:
#        return [i['value'] for i in options]
#    else:
#        raise PreventUpdate()
#
#@app.callback(
#    Output('checklist-container', 'children'),
#    [Input('product-choice', 'value')],
#    [State('product-choice', 'options'),
#     State('select-all', 'values')])
#def tester(chosenValues, availableChoices, selectALL):
#    
#    if len(chosenValues) < len(availableChoices) and len(selectALL) == 0:
#        raise PreventUpdate()
#
#    elif len(chosenValues) < len(availableChoices) and len(selectALL) == 1:
#        return  dcc.Checklist(id='select-all',
#                    options=[{'label': 'Select All', 'value': 1}], values=[])
#
#    elif len(chosenValues) == len(availableChoices) and len(selectALL) == 1:
#        raise PreventUpdate()
#
#    return  dcc.Checklist(id='select-all',
#                    options=[{'label': 'Select All', 'value': 1}], values=[1])  
#    
        
@app.callback(
        Output('bar-graph-by-model', 'figure'),
        [Input('product-choice', 'value')]
)
def updategraph(value):
    traces=[]
    for i in value:
        x=xTime
        ytemp=Table[i]
        traces.append(go.Bar(
            x=x,
            y=ytemp,
            name=i,
        ))
    return {
        'data': traces,
        'layout': go.Layout(
            )
   }
        
if __name__ == '__main__':
   app.run_server(debug=True, port=8051)

If the list shows the suggested values when the page is loaded, why does the graph stays empty ?

Hi @mikesmith1611 and @David22

I needed a similar thing and thank you for providing the idea of doing it. But, I have another question, what if I have a large set of options? doing a select all will crowd my display. How to handle such situations?

On my side I gave up with this workaround; At the end I had too many circular dependencies, and one is enough to break down everything :confused:

Hi @David22.

i’m not sure if your issue was resolved and/or what you mean by the graph staying empty when loaded. I tried your code as-is and this is what i get:

hi @mini_geek,

You basically need to uncomment the commented lines; I didnt notice that I copy-pasted my code with these lines commented.

Once done, if you reload the page, you can notice that the graph stays empty. It doesnt load the initial value in the picklist. Unless you actually pick a 4th item from the picklist.

So the idea is to have the same graph as I showed with a select all checkbox? @David22

@mini_geek Yes, and this checkbox should

  1. select all items from the picklist when checked,
  2. update itself as “unticked” once we remove items from the picklist.

Current code works fine for 1) and 2), but when the page loads the first time, and the picklist is filled with the default values, then the graph is not updated accordingly

I’ve managed to add a “Select All” option, and also show all data available when the dropdown is left blank.
Check this out: https://corporate-dash.herokuapp.com/ (explained in an article here: https://gabri-albini.medium.com/create-a-professional-dasbhoard-with-dash-and-css-bootstrap-e1829e238fc5)