Get the id of an element which was clicked on/howered over (the elements were created dynamically)

hello community,

I create some amount of some elements dynamically, that means that the number of them depends on some settings. That why I cannot hard code the callbacks for each element.

My question is whether it is possible to write a callback that stores the id of the element which was clicked or is currently howered over.

thank a lot

[EDIT]

I am checking the new feature according to the post

thanks to @chriddyp

Hi @cherepanovic, did you find a solution? Indeed I think here you can use a pattern-matching callback and use the Dash callback context to know exactly which component fired the callback.

I will try it out today

thanks!

pattern-matching callback is definitely a step forward for the framework…

My question is whether it is possible to write a callback that stores the id of the element which was clicked or is currently howered over .

I think I could use the timestamp and a global dict in order to store the last used id of an element, which was changed

would be something like that:

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

import time
import logging

app = dash.Dash(__name__, suppress_callback_exceptions=True)
lst = {'time': time.time(), 'id': None, 'value': None}

### aux methods ###

def set_last_id(ts, id, value=None):
    if lst['time'] < ts:
        lst['time'] = ts
        lst['id'] = id
        lst['value'] = value
    print(lst.items())

def display_controls(amount):
    # generate 2 dynamic controls based off of the datasource selections
    children = []
    each = 0
    while each < (amount):
        new_element = html.Div([
            dcc.Slider(
                id={
                    'type': 'dyn_slider',
                    'index': each
                },
                max=100,
                step=0.5,
                value=100,
            ),
            html.Div(
                id={
                    'type': 'dyn-output_slider',
                    'index': each
                }
            )
        ])
        children.append(new_element)
        each += 1
    return children

### layout ###

app.layout = html.Div([
    html.Div(id='current', style={'display': 'none'}),
    html.Div(id='current2', style={'display': 'none'}),
    html.Div(
        html.Div(id='dropdown-container', children=display_controls(4))
    ),
    dcc.Dropdown(
        id = 'dropdown',
        options=[
            {'label': 'New York City', 'value': 'NYC'},
            {'label': 'Montréal', 'value': 'MTL'},
            {'label': 'San Francisco', 'value': 'SF'}
        ],
        value='MTL'
    ),
    dcc.RadioItems(
        id = 'radio',
        options=[
            {'label': 'New York City', 'value': 'NYC'},
            {'label': 'Montréal', 'value': 'MTL'},
            {'label': 'San Francisco', 'value': 'SF'}
        ],
        value='MTL'
)

])

### callbacks ###

@app.callback(
    Output({'type': 'dyn-output_slider', 'index': MATCH}, 'children'),
    [Input({'type': 'dyn_slider', 'index': MATCH}, 'value')],
    [State({'type': 'dyn_slider', 'index': MATCH}, 'id')],
)
def display_output(value, id):
    set_last_id(time.time(), id, value)
    return html.Div('threshold of {} for label {}'.format(value/100, id['index']))

@app.callback(
    Output('current', 'children'),
    [Input('radio', 'value')])
def set_cities_options(value):
    set_last_id(time.time(), 'radio', value)
    return ''

@app.callback(
    Output('current2', 'children'),
    [Input('dropdown', 'value')])
def set_cities_options(value):
    set_last_id(time.time(), 'dropdown', value)
    return ''


if __name__ == '__main__':
    app.run_server(debug=True)
  • dynamical is this case the number of display_controls which will be set based on a dataset.

The last question is regarding the outputs in callback, in which way is it possible to use the same output in callbacks?