Callback using pattern matching throws error if there are elements that match the pattern(?)

Hello, I have created as minimal of an example as I can. The title is confusing because as far as I can tell the error I am actually getting is not caused by a singular issue, considering there are multiple posts with this error that have different issues. (Although none of them seem to have an actual solution posted either…)

How do I fix this?

Error: An object was provided as `children` instead of a component, string, or number (or list of those). Check the children property that looks something like:
{
  "0": {
    "props": {
      "children": "Delete",
      "id": {
        "index": 1,
        "type": "Delete"
      },
      "className": "delete",
      "n_clicks": 0
    },
    "type": "Button",
    "namespace": "dash_html_components"
  }
}

    at validateComponent (http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_11_1m1689279492.dev.js:2986:11)

    at BaseTreeContainer.getComponent (http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_11_1m1689279492.dev.js:3624:79)

    at BaseTreeContainer.render (http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_11_1m1689279492.dev.js:3800:19)

    at finishClassComponent (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom@16.v2_11_1m1689279492.14.0.js:17295:33)

    at updateClassComponent (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom@16.v2_11_1m1689279492.14.0.js:17245:26)

    at beginWork (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom@16.v2_11_1m1689279492.14.0.js:18755:18)

    at HTMLUnknownElement.callCallback (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom@16.v2_11_1m1689279492.14.0.js:182:16)

    at Object.invokeGuardedCallbackDev (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom@16.v2_11_1m1689279492.14.0.js:231:18)

    at invokeGuardedCallback (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom@16.v2_11_1m1689279492.14.0.js:286:33)

    at beginWork$1 (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom@16.v2_11_1m1689279492.14.0.js:23338:9)

The example I have created is here. Note the annotations because they are probably more helpful than the title.

I am running Dash version 2.11.1, on Windows.

from dash import Dash, html, Output, State, Input, Patch, ALL, ctx

app = Dash(__name__)
server = app.server

layout = html.Div([html.Button("Add", id="add", n_clicks=0), html.Div(id="my-div")])


@app.callback(
    Output("my-div", "children", allow_duplicate=True),
    Input("add", "n_clicks"),
    prevent_initial_call=True,
)
def add_row(button_clicked):
    # The error is only thrown when the Add button is clicked and presumably when this callback is run.

    patched_list = Patch()

    def new_row():
        return html.Button(
            children="Delete",
            id={"index": button_clicked, "type": "Delete"}, # When ID is removed no error is thrown
            className="delete",
            n_clicks=0,
        )

    patched_list.append(new_row())
    return patched_list


@app.callback(
    Output("my-div", "children", allow_duplicate=True),
    Input({"index": ALL, "type": "Delete"}, "n_clicks"),
    State({"index": ALL, "type": "Delete"}, "id"),
    prevent_initial_call=True,
)
def delete_row(n_clicks, id):
    # When this callback is missing no error is thrown.

    patched_list = Patch()
    triggered_id = ctx.triggered_id

    del patched_list[triggered_id]

    return patched_list


if __name__ == "__main__":
    app.layout = layout
    app.run_server(debug=True, use_reloader=True)

I combined two separate examples on the pattern-matching callbacks page so I have no idea if I did it correctly.

Thanks.

@RGasque Hello!

I believe id in html.Button() (what you are returning) should be a string, not a dictionary. If you need to specify a type, then you may do so using the type parameter (also a string). You might want to review the documentation for more details.

@trlemon Thanks.
Is there a different element I should be using than Button for pattern-matching callbacks? The documentation doesn’t seem to have anything else listed.

@trlemon I don’t think the documentation ever states id can be a dictionary despite it being a feature present in multiple tutorials and examples in the documentation.

@RGasque I’ll have to play around with your example a little more. I’m stumped for now.

@trlemon

This is the page with the examples I based my solution on.

Hi, what are you trying to do with the Patch()?

Are you trying to delete the Buttons?

Side note: If you are using pattern matching callbacks, the triggered_id is a dictionary, with the keys ìndex and type`

If I understand you correctly, you are interested in the index:

triggered_index = ctx.triggered_id.index

Hello @AIMPED, thank you for answering and sorry for responding so late! That was indeed what was causing the error, but it still does not do what I want. I am trying to use the Patch to delete rows of a table, I think my minimal example was in fact too minimal to be practical.

I have solved it, in a way that makes me feel stupid because I should have just copied the example the entire time D:

@app.callback(Output('my-div', 'children', allow_duplicate=True),
              Input({"index": ALL, "type": "Delete"}, 'n_clicks'),
              prevent_initial_call=True)
def delete_row(n_clicks):
    
    patched_list = Patch()
    values_to_remove = []
    for i, val in enumerate(n_clicks):
        if val > 0:
            values_to_remove.insert(0, i)
    for v in values_to_remove:
        del patched_list[v]
    return patched_list
    # This is verbatim the example at the bottom of the pattern matching callbacks page, other than the check being an inequality rather than a truthy check

Always overthink things… Thanks everyone for helping nonetheless. Although I don’t think this is very efficient, I am working with human input here so it should have no impact.

1 Like