Black Lives Matter. Please consider donating to Black Girls Code today.

Change id selector breaks callback functionality

Hi,

I have this strange issue where if I change the ids of certain elements, the callbacks no longer work. Here’s my code:

import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import pandas as pd
from app import app, cache
from helper import *

CACHE_TIMEOUT = 3600

#############################
# Data Manipulation / Model #
#############################

def activity_query(date_col, start_date, end_date, date_group, group="", filter_dict={}):
    addl_filters = ""
    if not all(x is None for x in filter_dict.values()):
        for col, flt in filter_dict.items():
            if not flt:
                continue
            addl_filters += "AND {0} IN {1} ".format(col, create_sql_list(flt))

    if group == "":
        group_select = ""
    elif group == "usergroup":
        group_select = (
            ", CASE "
              "WHEN usergroup IN ('Active Member', 'Ex Member', 'Banned', 'Test') THEN 'Member' " 
              "ELSE usergroup "
            "END AS grp ")
        group = ', grp'
    else:
        group_select = ', ' + group + ' AS grp '
        group = ', grp'
        
    query = (
        "SELECT {} AS date, ".format(sql_date_group(date_col, date_group)) +
          "COUNT(*) AS count" + 
          group_select + 
        "FROM dashboard_activity "
        "WHERE {0} BETWEEN '{1}' AND '{2}' ".format(date_col, start_date, end_date) + 
          addl_filters +
        "GROUP BY date{};".format(group))
    
    return query

usergroup_filters = {'Members': 'Members', 'Administrators': 'Administrator', 'Moderators': 'Moderator'}
    
###########################
# Dashboard Layout / View #
###########################

layout = html.Div([
    html.Div([
        html.H3('Forum Activity'),
        html.Img(src='/assets/img/info.png', className='desc-tooltip')
    ], className='chart-title'),
    
    html.Div([
        html.Div([
            html.Label('Group by:', className='control-title'),
            dcc.Dropdown(
                id='activity-group',
                options=[
                    {'label': 'Activity Type', 'value': 'activity'},
                    {'label': 'User Group', 'value': 'usergroup'},
                    {'label': 'Forum Section', 'value': 'cat_1_clean'}],
                value='activity', clearable=False, className='control-item')
        ], className='control-group'),
        
        dcc.Checklist(
            options=[{'label': 'Filters', 'value': 'show'}],
            id='toggle-filters', className='toggle-filters', values=[]),
        
        html.Div([
            dcc.RadioItems(
                id='activity-date-grouping',
                options=[
                    {'label': 'Day', 'value': 'D'},
                    {'label': 'Week', 'value': 'W'},
                    {'label': 'Month', 'value': 'M'}],
                value='D', className='date-group-items')
        ], className='date-group')
    ], className='chart-control'),
    
    html.Div([
        html.Div([
            dcc.Dropdown(
                options=create_flt_options('activity', 'dashboard_activity'),
                id='activity-type-flt', placeholder='Activity', multi=True, className='control-item'),
                
            dcc.Dropdown(
                options=create_flt_options('usergroup', 'dashboard_activity', usergroup_filters),
                id='activity-usergroup-flt', placeholder='User Group', multi=True, className='control-item'),
                
            dcc.Dropdown(
                options=create_flt_options('cat_1_clean', 'dashboard_activity'),
                id='activity-forum-flt', placeholder='Forum Section', multi=True, className='control-item'),
                
            dcc.Dropdown(
                id='activity-subforum-flt', disabled=True,
                placeholder='Forum Sub-Section', multi=True, className='control-item'),
        
            html.Button('Set Filters', id='filter-submit', className='filter-submit', n_clicks=0),
            html.Button('Clear', id='filter-clear', className='filter-clear', n_clicks=0)
        ], className='control-filter')
    ], id='hidden-filters', className='hidden-filters', hidden=True),
    
    html.Div([
        dcc.Graph(id='stm-activity', config={'displayModeBar': False})
    ], className='chart-display')
])

###############################################
# Interaction Between Components / Controller #
###############################################

# Show filters
@app.callback(
    Output('hidden-filters', 'hidden'),
    [Input('toggle-filters', 'values')])
def display_act_filters(values):
    if 'show' in values:
        return False
    else:
        return True
        
# Hide filters upon filter submit
@app.callback(
    Output('toggle-filters', 'values'),
    [Input('filter-submit', 'n_clicks')])
def hide_act_upon_click(flt_clicked):
    return ['']
    
# Clear activity type filters upon clear click
@app.callback(
    Output('activity-type-flt', 'value'),
    [Input('filter-clear', 'n_clicks')])
def hide_activity_type_flt(flt_clr_clicked):
    return None
    
# Clear usergroup filters upon clear click
@app.callback(
    Output('activity-usergroup-flt', 'value'),
    [Input('filter-clear', 'n_clicks')])
def hide_usergroup_flt(flt_clr_clicked):
    return None
    
# Clear forum filters upon clear click
@app.callback(
    Output('activity-forum-flt', 'value'),
    [Input('filter-clear', 'n_clicks')])
def hide_forum_flt(flt_clr_clicked):
    return None
    
# Clear subforum filters upon clear click
@app.callback(
    Output('activity-subforum-flt', 'value'),
    [Input('filter-clear', 'n_clicks')])
def hide_subforum_flt(flt_clr_clicked):
    return None
        
# Update Forum Sub-Section Filter Options
@app.callback(
    Output('activity-subforum-flt', 'options'),
    [Input('activity-forum-flt', 'value')])
@cache.memoize(timeout=CACHE_TIMEOUT)
def update_subforum_options(forum_flt):
    subforum_options = create_flt_options('cat_2_title', 'dashboard_activity', filter_dict={'cat_1_clean': forum_flt})
    return subforum_options

# Update Forum Sub-Section Filter Access
@app.callback(
    Output('activity-subforum-flt', 'disabled'),
    [Input('activity-forum-flt', 'value')])
def update_subforum_state(forum_flt):
    if forum_flt:
        return False
    return True
    
# Update STM Forum Activity Chart
@app.callback(
    Output('stm-activity', 'figure'),
    [Input('date-picker-range', 'start_date'),
     Input('date-picker-range', 'end_date'),
     Input('activity-date-grouping', 'value'),
     Input('activity-group', 'value'),
     Input('filter-submit', 'n_clicks')],
    [State('activity-type-flt', 'value'),
     State('activity-usergroup-flt', 'value'),
     State('activity-forum-flt', 'value'),
     State('activity-subforum-flt', 'value')])
@cache.memoize(timeout=CACHE_TIMEOUT)
def update_activity(start_date, end_date, date_group, act_group, flt_clicked, act_flt, usergroup_flt, forum_flt, subforum_flt):
    start_date = pd.period_range(start_date, start_date, freq=date_group).start_time[0]
    end_date = pd.period_range(end_date, end_date, freq=date_group).end_time[0]
    
    if usergroup_flt:
        if 'Members' in usergroup_flt:
            usergroup_flt.extend(['Ex Member', 'Active Member'])
            usergroup_flt.remove('Members')
    
    filter_dict = {}
    filter_dict['activity'] = act_flt
    filter_dict['usergroup'] = usergroup_flt
    filter_dict['cat_1_clean'] = forum_flt
    filter_dict['cat_2_title'] = subforum_flt
    
    query = activity_query('datetime', start_date, end_date, date_group, act_group, filter_dict)
    activity = pd.read_sql_query(query, engine_an)
    activity = gen_cnst_df(activity, 'date', 'count')
    df_shape = (activity['x'].max() - activity['x'].min()).days / date_group_map[date_group]
    
    return {
        'data': gen_traces(activity, 'bar'),
        'layout': dict(
            barmode='stack', showlegend=True,
            legend=dict(orientation='h', xanchor='center', yanchor='middle', x=0.5, y=1.1),
            font=dict(family='Roboto', size=14, color='#000'),
            xaxis=gen_ts_xaxis(df_shape, date_group, start_date),
            yaxis=dict(title='Activity Count')
        )
    }

This works fine. I know there are quite a few functions called from imported libraries here, but I don’t think it’s necessary to include them. Yet if I change the following ids, for some reason, the functionality breaks, and the graph no longer gets displayed, nor does the show/hide filter button work as intended. I wanted to change the following ids:
filter-submit
filter-clear
toggle-filters
hidden-filters

and just prepend ‘activity-’ at the beginning. Note that this is part of a larger app, and is just 1 page.

Also, I’m always open to feedback on how to improve my code =)