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


#1

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?


#2

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

@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)

#4

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.


Multiselect with large number of elements (>15)
#5

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.