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

Open a modal for a each row item in table

Hello All,

I am very new to dash. I am generating a dash html table and item in each row of a particular column is a link. When an item is clicked, I want a modal to open and display the contents of the selected item.

def Table(dataframe):
    rows = []
    for i in range(len(dataframe)):
        row = []
        for col in dataframe.columns:
            value = dataframe.iloc[i][col]
            # update this depending on which
            # columns you want to show links for
            # and what you want those links to be
            if col == 'id':
                cell = html.Td(html.A(href=value, children=value))
            else:
                cell = html.Td(children=value)
            row.append(cell)
        rows.append(html.Tr(row))
    return html.Table(
        # Header
        [html.Tr([html.Th(col) for col in dataframe.columns])] +
        rows
    )

Depending on the ‘value’ , I want to display the contents of modal. How can I do this?

Hi @sahanar17,

Welcome, and thanks for using Dash!

I think you can use Dash callbacks to achieve what you are looking for. Now, if by “contents of the selected item” you mean the webpage that that the URL in the html.A(href ...) points to, you’ll need an html.Iframe. You’ll want to assign an ID to the html.A so that you can use it in a callback, and then have that callback update the html.Iframe's src parameter with the href. You can put the html.Iframe in a wrapper div like a modal.

I just created an example for another community member that illustrates using a callback to open a “modal” when a button within an html.Table is clicked. Hopefully, what you want to do is similar enough to the example that it will give you a good start:

(from Adding a button inside a html.table)

Obviously, you’ll want to replace the “I popped up after you clicked that button” children of the modal-container with your html.Iframe.

PS: I took the liberty of adding formatting to your posts’ code; I hope that’s OK. It’s a lot easier to read code when it’s wrapped in

backticks

, either using ``` {code} ```, or using the WYSIWYG editor’s </> icon.

Thank you so much for your response. I went ahead and modified my code based on your suggestion. But the pop up occurs even before clicking on the button. Please tell me what I am doing wrong.

I have over 1500 rows in the table and so generating id is the loop. I am also passing all of them as input to the callback function. Please tell me what I am doing wrong.

def generate_table(dataframe):
    id=1
    rows = []
    for i in range(len(dataframe)):
        row = []
        for col in dataframe.columns:
            value = dataframe.iloc[i][col]
            # update this depending on which
            # columns you want to show links for
            # and what you want those links to be
            if col == 'API_LIST':
                cell = html.Td(html.Button("%s" %value, id="input_{}".format(id)))
                id=id+1
            else:
                cell = html.Td(children=value)
            row.append(cell)
        rows.append(html.Tr(row))
    return html.Table(
        # Header
        [html.Tr([html.Th(col) for col in dataframe.columns])] +

        rows
    )


app.layout = html.Div([html.Div([generate_table(df)]),html.Div(id='modal-container')])



modal_style = {
    'position': 'absolute',
    'width': '50%',
    'height': '50%',
    'top': '50%',
    'left': '50%',
    'transform': 'translate(-50%, -50%)',
    'border': '5px solid lightcoral',
    'background': 'lightsalmon'
}


@app.callback(
    Output('modal-container', 'children'),
    [Input('input_{}'.format(i), 'n_clicks')for i in range(1,len(df)+1)])


def update_output(*n_clicks):
    if n_clicks is not None:
        return html.Div(
            'I popped up after you clicked that button',
            style=modal_style
        )


app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})

if __name__ == '__main__':
    app.run_server(port=8050, host='0.0.0.0')