Pattern-matching callbacks with non-existent components?

I’m trying to trigger a pattern-matching callback with a component that is not present in the original layout but added afterwards. This does not seem to work.

See the MWE hereinafter

import dash
from dash import dcc, html, Input, Output, State, clientside_callback, ALL
import plotly.graph_objects as go

app = dash.Dash(__name__)

app.layout = html.Div(
    [
        html.Button("Generate Figure", id="generate-btn", n_clicks=0),
        html.Div(
            id="graph-container",
            children=[],  # Initially empty
            style={"display": "none"}  # Initially hidden
        ),
    ]
)

@app.callback(
    [
        Output("graph-container", "children"),
        Output("graph-container", "style"),
    ],
    [Input("generate-btn", "n_clicks")],
    prevent_initial_call=True,
)
def update_figures(n_clicks):
    children = [
        dcc.Graph(
            id=dict(type="figure", id="prec-climate-daily"),
            style={"height": "45vh"},
            config={"responsive": True},
            figure=go.Figure(
                            data=[go.Scatter(x=[0, 1, 2], y=[0, 1, 0], mode="lines")])
        ),
    ]
    return children, {"display": "block"}

@app.callback(
    Input(dict(type="figure", id=ALL), "figure"),
    State(dict(type="figure", id=ALL), "id"),
)
def test(figure, id):
    print("test")

if __name__ == "__main__":
    app.run(debug=True)

The Graph component with id=dict(type="figure", id="prec-climate-daily") is not present in the layout when initializing the app, but is only added by the update_figures callback.
Unfortunately the callback test is never triggered (nor I see any error in the Python or JS console).
I thought the advantage of pattern-matching callback was that one could use them to trigger also with dynamically created components, however it seems that the only way to trigger them is to have the Graph object initially in the layout.

Hi @guidocioni your callback is never triggered because you never change the input of this callback:

Input(dict(type="figure", id=ALL), "figure"),

I’m not sure I understand this.

The callback update_figures indirectly changes the figure property of the Graph component with id=dict(type="figure", id="prec-climate-daily"). This should match Input(dict(type="figure", id=ALL), "figure").

To be honest this works when the Graph object is created in the initial app layout: the only difference here is that this component is created AFTER the app layout has been initialized (but the pattern matching logic was working before).

Hi @guidocioni
I think I faced the same issue abd created an issue for that Adding new Pattern Matching components don't trigger their related callback · Issue #3191 · plotly/dash · GitHub.

I think you’re right, although I’ve been trying to understand your MWE and is already too complex for my small brain :smiley:
It seems you’re also trying to add new elements (that are not present the first time the app layout is rendered) and these do not seem to trigger callbacks.

I’m still confused to whether components registered AFTER the initial app layout can be used in callbacks. I seem to remember that for regular non-pattern-matching callbacks only the elements present in the initial app layout were registered and available to be used as Input/Output/State in callbacks. And I thought that pattern-matching callbacks would fix this behaviour. In fact, using regular callbacks with components not registered in the initial layout will trigger an error when starting the app, but this does not happen when using pattern-matching callbacks. But now I’m wondering if I maybe did not understand this correctly and the behaviour is independent from using either normal or pattern-matching callbacks.

I also tried to use clientside callback but these were also not triggered.

Yeah I had deeper look now too and it seams to be a different usecase. My callback generates the components that should trigger it again. That said, I ran your example and got to work with adding an output to the callback, but I would expect that the no output callback would also work with pattern matching inputs. Maybe something raise

You’re right! It does actually get triggered with an output… that’s weird.

I think what is happening is that, when an Output is used, then the callback is registered when the app starts, because the component the Output is pointing at does exist in the app layout, so it doesn’t matter if the Input does not. Instead, when using no Output the callback is never registered because no input of the callback is in the initial app layout.

Honestly I don’t think this is intended behaviour, but I may be wrong…