Is it possible to generate callbacks with random Inputs?

Hi there,

my question is: is it possible to generate callback with not predefined number of inputs?

For example, I parse file by clicking button, generate list of id’s for Inputs, and then want to generate as much Inputs in callback, as id’s in list.

example:

inputslist=[]
idforinputs=['id1','id2','id3','id4','id5']
for elements in idforinputs:
 inputslist.append(dcc.Input(id=elements))
 

app.callback(Output(**something**),inputlist)

Also, the other question is:
is there a way to connect different inputs to one output? I tried to make a workaround for the first question and decided to make callback for every element I create. However, because of the fact that reaction is the same (for example, customer clicked generated link and data should be transfered to another app in it’s Div) I get error:
dash.exceptions.DuplicateCallbackOutput:

We’re actively building a solution for this right now. See https://github.com/plotly/dash/issues/475 for discussion.

Before that’s out, the only solution I’m aware of is to pre-create as many elements as you’re ever going to support, and leave any unused ones hidden.

Re: your second question: no, a given output needs to be specified by only one callback. Otherwise it would be ambiguous.

1 Like

Hi Alex, thanks for the answer!

So, does it meant that I should create, lets say, 30 insivible elements, like html.Div, for example, and track down their children property in callback?

to make it clear:
Lets say I created 30 html.Div’s (all invisible).
In first callback I generate, lets say, 30 html.A objects
I write every object ,every html.A, to every Div I created above.
Then I create second one, big callback,where Inputs are ‘children’ properties of those 30 Div’s, and Output is one - my second app’s main Div
Now I only need to know, which link from the generated links was clicked by user. Since every of 30 Div’s will hold something like that:
html.A('link1_name', href='/apps/app2', id='link1_id')
I still cant imagine how to understand that exactly this element was clicked.
Would appreciate any advice

oh if you can do it through the app’s URL I think there’s a much easier way - use dcc.Link and dcc.Location - see https://dash.plot.ly/urls and notice the callback that responds to the location need not serve the entire page, it can be just a part.

Now if you do it that way your last question may not be relevant right now, but since you asked:

I still cant imagine how to understand that exactly this element was clicked.

yeah we need to document this better… see dash.callback_context.triggered, described in FAQs | Dash for Python Documentation | PlotlyQ: How do I determine which Input has changed?

But in callback as input we use ‘children’ property of Div, not html.A
And if I will use dash.callback_context.triggered , then I will receive id of the Div, while I need id of the html.A

I was suggesting replacing the html.A elements with dcc.Link - what happens then is all of these write to the page URL, and you can then read this back in via dcc.Location - its pathname prop effectively tells you which element was clicked.

But if you really want to do it with html.A, the route I’d take is: pre-create 30 html.A elements, but hide the unused ones. Then your second callback takes the n_clicks prop of all 30 html.A elements as inputs; dash.callback_context.triggered will tell you which one was clicked.

Got it, thanks! Will try it now

I finally made it and decided to use transfer info via dcc.Link (so all links are unique and I’m analysing “path” property to parse it further).
However, I faced new problem:
1) dcc.Link have no property to open link in new tab (while html.A have property “target”), and ofcourse it is possible to open link in new tab with right click or with scroll click, but ‘typical’ user use left click for this.Is it possible to change behaviour of dcc.Link to be opened in new tab by default?

Oh if you want a new tab, you can just use html.A - but keep dcc.Location for setting the page contents. The key reason to use dcc.Link is to avoid reloading the page, so the transition can be much faster. But in a new tab there’s no avoiding recreating the environment so nothing is lost with html.A.

Got it, thank you very much!
I didn’t realize that this is a common approach- transfer data via url. The problem of my experience, ofcourse.

Hi Alex, lets say I generate a ‘n’ number of cards, every card will display a link, and Im working on something like on clicking on the link, the link should disappear, for that I can change the style , to update that specific card, we should have id, I generated a id for each card like - "id = "link-{i} so the question is how can we specify in callbacks ? the cards are generated dynamically, - it may 1- 50 cards at first or it may increase or decrease,

I cant have all back for all those id right ?
@app.callback(output('link- ?

Hello @Vani,

Welcome to the community.

I think you are hunting for pattern-matching:

You can use ALL, MATCH to update each individual card based upon the index, so you can use this to hide selected links. :slight_smile:

1 Like

how ? few doubts here,

@app.callback(output('link- ? , style), Input("link-? ,style))

for example 1st time it will generate 50 cards so, "link-1,…link-50 would be the link id, how do you write this ? I tried with “link-*” it did not work ?

Please take a look at how the pattern-matching callback is done, there is a different structure. :slight_smile:

Hello, here I’m dynamically generating cards, in card, there would be a link “click here” on clicking on it , the link should replace with input field but some how , it is not calling the method itself - replace_link_with_input(n_clicks):

any help on this ?

def make_card(linkVar,index):
    return dbc.Card(
        [
            dbc.Row(
                [

                    dbc.Col(
                        dbc.CardBody(
                            [
                                
                                dbc.Row([
                                    dbc.Col([
                                        html.A(
                                            "Click here",
                                            id={"type": "update-link", "index": index},
                                            href=linkVar,
                                            target="_blank",
                                            style={"display": "block"},
                                            n_clicks=0
                                        ) if linkVar else None,
                                        dbc.Input(
                                            id={"type": "update-input", "index": index},
                                            type="text",
                                            placeholder="Enter Name",
                                            style={"display": "none"}
                                        ),
                                    ],
                                        width=2
                                    )
                                ]), 

                            ]
                        ),
                    ),
                ],
            )

        ],
        className="w-100 mb-3",
        id={"type": "card", "index": index}
    )


@app.callback(
    [
        Output({"type": "update-link", "index": MATCH}, "style"),
        Output({"type": "update-input", "index": MATCH}, "style")
    ],
     [Input({"type": "update-link", "index": ALL}, "n_clicks")],
    # [State({"type": "card", "index": ALL}, "id")]
)
def replace_link_with_input(n_clicks):
    index = int(ctx.triggered[0]['prop_id'].split(',')[1].split(':')[1])

    print(ctx.triggered[0]['prop_id'])
    output_styles = [
        {"display": "none"} if "update-link" in ctx.triggered[0]['prop_id'] else {"display": "block"},
        {"display": "block"} if "update-link" in ctx.triggered[0]['prop_id'] else {"display": "none"}
    ]
    return output_styles

Hello @Vani,

You should just be able to change your intou from ALL to MATCH. Everything else looks good.

And you’ll only need to return the updates for one index. MATCH tells it to match based upon the index, and only update that one. :grin:

yes, yes I solved it, I tried commenting state and printed id, all id’s were printed then changed to MATCH . it worked !

1 Like