# Callback not working at all in my app

**URL:** https://community.plotly.com/t/callback-not-working-at-all-in-my-app/81454
**Category:** Dash Python
**Tags:** question
**Created:** [January 9, 2024, 9:52am UTC](https://community.plotly.com/t/callback-not-working-at-all-in-my-app/81454 "2024-01-09T09:52:15Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![ldeco](https://avatars.discourse-cdn.com/v4/letter/l/a587f6/32.png) [@ldeco](https://community.plotly.com/u/ldeco)
#### Post date: [January 9, 2024, 9:52am UTC](https://community.plotly.com/t/callback-not-working-at-all-in-my-app/81454/1 "2024-01-09T09:52:15Z")

</div>

Hello everyone,

I am building an app for my job, it is my first app so I tried to make it scalable and easy to maintain. I separated many things in different files and folders to keep the code clean. When I am navigating on the app, I first see a homepage, then I must select a client from a dropdown, once done two buttons appears in the navbar, I must select a cycle (revenue analysis, logistic analysis…) and then a dashboard for this client and this cycle is shown. Everything is dynamic, as soon as I add a new folder in my clients folder, I can select it from the dropdown. Same for the cycle, as soon as I add a new folder in the client folder, it is available as a new cycle. Everything is almost perfect, yet, when selecting a client and a cycle, I have a layout that is just 4 tabs with content for the 4 tabs. I can see the 4 tabs and interact with them but the content inside each tab is not showing. I have a callback that populate the tabs’ content when I select one but it is not working. I put a print statement in the callback but it does not show in my terminal so the callback is definitly not firing. I don’t have issue error on my terminal nor on the debug. I spent 5 hours and I still cannot see what is happening. If someone has suggestions, I am all ears!!

tl;dr: the callback in my index.py is not working, I can only see the tabs but not the content inside.

Here is the structure of my app:

```auto
app_directory/
│
├── app.py # Main file where the Dash app is initialized
│
├── assets/ # Directory for CSS, JS, and other static files
│ └── ... # Static files like custom stylesheets, scripts, etc.
│
├── clients/ # Directory for client-specific modules
│ └── GIE/ # Sub-directory for the GIE client
│ └── revenues/ # Sub-directory for the revenues cycle of the GIE client
│ └── index.py # File for the GIE client's revenues layout and callbacks
│
├── default/ # Directory for default layouts
│ ├── home/              
│ │ └── home_layout.py # Layout for the home page
│ ├── summary/           
│ │ └── ... # Layout for the summary page
│ ├── reporting/         
│ │ └── ... # Layout for the reporting page
│ └── client/            
│ └── ... # Layout for client-specific pages
│
├── functions.py # Utility functions, including dynamic layout imports
│
└── data/ # Directory for datasets
    ├── GIE/ # Data specific to the GIE client
    │ └── CA_2022.csv # Dataset file
    └── ... # Other datasets

```

Here is the code for app.py:

```auto
# app.py
import os
import dash
import dash_bootstrap_components as dbc
from dash import html, dcc, callback_context
from dash.dependencies import Input, Output

# Import functions
from functions import get_cycles, format_cycle_name, import_cycle_layout

# Import layouts from the 'default' folder
from default.home.home_layout import home_layout
from default.summary.summary_layout import summary_layout
from default.reporting.reporting_layout import reporting_layout
from default.client.client_layout import client_layout

# Initialize the app with the external LUX theme from Bootswatch
app = dash.Dash( __name__ , external_stylesheets=[dbc.themes.LUX])
app.config.suppress_callback_exceptions = True # Allows us to navigate between pages
server = app.server

# List of clients (dynamically generated from the 'clients' folder)
client_options = [{'label': client, 'value': client} for client in os.listdir('clients') if client not in [" __pycache__", " __init__.py"]]

# Initial Navbar setup with the logo on the far left
navbar = dbc.Navbar(
    dbc.Container([
        # Logo on the far left
        html.A(
            html.Img(src=dash.get_asset_url("logo-hdm.png"), height="50px"),
            href="/"
        ),
        # Navigation items
        dbc.NavbarBrand("HDM FINANCIAL EXPLORER", href="/", className="ml-2"),
        dbc.Nav(
            [
                # dbc.NavItem(dbc.NavLink("Home", href="/")),
                dbc.NavItem(dbc.NavLink("Général", href="/summary")),
                dbc.DropdownMenu(
                    children=[dbc.DropdownMenuItem(client['label'], href=f"/client/{client['value']}") for client in client_options],
                    nav=True,
                    in_navbar=True,
                    label="Sélectionner un Client",
                ),
                # Placeholder pour le dropdown cycle qui est caché si on ne choisit pas un client
                html.Div(id='cycle-dropdown-container', children=[], style={'display': 'none'}),
                # Placeholder pout le boutton reporting qui est caché si on ne choisit pas un client
                html.Div(id="reporting-button-container", children=[
                    dbc.NavItem(dbc.NavLink("Reporting", href="", id="reporting-button"))
                ], style={"display": "none"})
            ],
            className="ml-auto", # Pushes the nav items to the right
        ),
    ]),
    color="primary",
    dark=True,
)

# Define the initial layout
app.layout = html.Div([
    dcc.Location(id='url', refresh=False), # Tracks the URL
    navbar,
    html.Div(id='page-content') # Content will be rendered in this element
])

# Callback for multi-page app
@app.callback(Output('page-content', 'children'),
              [Input('url', 'pathname')])
def display_page(pathname):
    path_parts = pathname.strip('/').split('/')
    if len(path_parts) == 3 and path_parts[0] == 'client':
        client_id = path_parts[1]
        cycle_name = path_parts[2]
        # Use the import_cycle_layout function to dynamically load the layout
        return import_cycle_layout(client_id, cycle_name) 
    elif len(path_parts) == 2 and path_parts[0] == "client":
        return client_layout(path_parts[1])
    elif pathname == '/summary':
        return summary_layout
    elif pathname == '/':
        return home_layout
    else:
        return '404 - Not found'

# Updated callback for the navbar to include dynamic Cycle dropdown and Reporting button
@app.callback(
    [Output('cycle-dropdown-container', 'children'),
     Output('cycle-dropdown-container', 'style'),
     Output('reporting-button-container', 'style'),
     Output('reporting-button', 'href')], # Update the button's URL dynamically
    [Input('url', 'pathname')])
def update_navbar(pathname):
    if '/client/' in pathname:
        split_path = pathname.split('/')
        client_id = split_path[2]
        cycle = split_path[3] if len(split_path) > 3 else None

        cycles = get_cycles(client_id)
        cycle_dropdown = dbc.DropdownMenu(
            children=[dbc.DropdownMenuItem(format_cycle_name(cycle_name), href=f"/client/{client_id}/{cycle_name}") for cycle_name in cycles],
            nav=True,
            in_navbar=True,
            label="Cycle",
            id='cycle-dropdown'
        )

        # Ensure the reporting URL doesn't duplicate '/reporting'
        reporting_url = f"/client/{client_id}/{cycle}/reporting" if cycle else f"/client/{client_id}/reporting"
        return cycle_dropdown, {}, {}, reporting_url

    return [], {'display': 'none'}, {'display': 'none'}, ""

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

```

Here is the code for functions.py:

```auto
"""
"""
import os
from dash import html
import importlib

# Trouver le nom du cycle en parcourant les fichier
def get_cycles(client_name):
    client_path = os.path.join('clients', client_name)
    if os.path.exists(client_path):
        return [cycle for cycle in os.listdir(client_path) if os.path.isdir(os.path.join(client_path, cycle)) and cycle not in [" __pycache__"]]
    return []

# Avoir dans le dropdown Cycle le nom en du cycle en capital et avec un espace au lieu d'un dash
def format_cycle_name(name):
    return name.replace('_', ' ').upper()

# Importer les layouts client de façon dynamiques
def import_cycle_layout(client_id, cycle_name):
    try:
        # Construct the module path and import the layout
        module_path = f'clients.{client_id}.{cycle_name}.index'
        cycle_module = importlib.import_module(module_path)
        return cycle_module.layout
    except (ModuleNotFoundError, AttributeError):
        # Return an error message or default layout if the specific layout doesn't exist
        return html.Div(f"Layout not found for client {client_id} and cycle {cycle_name}")

```

and finally the code for the index.py file:

```auto
from dash import html, dcc, Input, Output
from dash import callback
from dash.dash_table import DataTable
import dash_bootstrap_components as dbc
from dash.exceptions import PreventUpdate
# from app import app
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np

from assets.couleurs import couleurs_theme

# from functions import sequencialite

# Import du Dataset
ca_2022_df = pd.read_csv("data/GIE/CA_2022.csv", index_col=False)

# Ordonner les mois pour les graphiques:
mois_ordonés = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']
ca_2022_df['Mois'] = pd.Categorical(ca_2022_df['Mois'], categories=mois_ordonés, ordered=True)
    
# App layout
layout = html.Div([
    dcc.Tabs(id="tabs_gie", value="tab_vision_globale", children=[
        dcc.Tab(label="Vision Globale", value="tab_vision_globale"),
        dcc.Tab(label="Interne Rhum", value="tab_interne_rhum"),
        dcc.Tab(label="Externe Négoce", value="tab_externe_negoce"),
        dcc.Tab(label="Séquentialité", value="tab_sequentialite")
    ]),
    html.Div(id="contenu_tabs")
])

@callback(Output("contenu_tabs", "children"),
              Input("tabs_gie", "value"))

def afficher_contenu(tab):
    return html.Div("Test content")

```

Here is a screenshot of the tab but “Test Content” must be shown.

 ![test](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/5/0/507bbe7cc02b3e5e1cb182d3964bcf0bc104f1da.png)

Thanks in advance,  
Louis

---

<div class="post-metadata">

### Author: ![AIMPED](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/aimped/32/21758_2.png) [@AIMPED](https://community.plotly.com/u/AIMPED)
#### Post date: [January 9, 2024, 10:23am UTC](https://community.plotly.com/t/callback-not-working-at-all-in-my-app/81454/2 "2024-01-09T10:23:14Z")

</div>

> [@ldeco](#):
>
> ```auto
> # Define the initial layout
> app.layout = html.Div([
> dcc.Location(id='url', refresh=False), # Tracks the URL
> navbar,
> html.Div(id='page-content') # Content will be rendered in this element
> ])
> 
> ```

Hi @ldeco, is there a reason for not using the [pages feature](https://dash.plotly.com/urls#dash-pages)? It usually simplifies the creation of multipage apps a lot.

---

<div class="post-metadata">

### Author: ![ldeco](https://avatars.discourse-cdn.com/v4/letter/l/a587f6/32.png) [@ldeco](https://community.plotly.com/u/ldeco)
#### Post date: [January 9, 2024, 10:26am UTC](https://community.plotly.com/t/callback-not-working-at-all-in-my-app/81454/3 "2024-01-09T10:26:57Z")

</div>

I did not know about this, I will take a look!
