0
votes

Is it possible to give inputs to a callback function which is inside another callback? In the below example I need to process each of the dict_item['Name'] which is getting passed from the outer call back function in a for loop.

# Outer Call back
@app.callback(
    dash.dependencies.Output("dummydiv", "children"),  # Dummy Output
    [dash.dependencies.Input("interval1", "n_intervals")],  # Interal Triger
    [dash.dependencies.Input("table", "data")],
)  # dcc.Store which stores values
def use_table(n, data):
    print(type(data))
    print("Outer Called")

    if data:
        for dict_item in data:

            @app.callback(
                dash.dependencies.Output(
                    "lable1", "children"
                ),  # Output to print the values in a llop
                dash.dependencies.Input(dict_item["Name"]),
            )
            def printing(s_name):

                sn = s_name
                print(sn)

                return sn  # Return "Name to Print" to id "Lable1"

        return ""  # Dummy String  - Print Nothing to id "dummydiv"
    return dash.no_update

Unfortunately, I am not able to pass the input parameter to the inner call back function. It returns the below error:

dash.dependencies.Input(dict_item['Name]) TypeError: init() missing 1 required positional argument: 'component_property'

How do I pass the variable from the outer call back to the inner call back? Or is there any other possible way to implement this logic?

Edit: Reproducible Code

import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_table
from dash.dependencies import Output, Input, State
from datetime import datetime

user_key = "Name"
# Setup table.
columns = ["Name", "Age", "Place", "Vaccinated"]

table = dash_table.DataTable(
    columns=[{"name": column, "id": column} for column in columns], data=[], id="table"
)
# Create app.


app = dash.Dash(prevent_initial_callbacks=True)
app.layout = html.Div(
    [
        html.Div(
            [dcc.Input(id=column, value=column) for column in columns]
            + [html.Button("Save", id="save"), dcc.Store(id="cache", data=[]), table]
        ),
        html.Div(
            [
                dcc.Interval(id="interval1", interval=5 * 1000, n_intervals=0),
                html.H1(id="dummydiv", children=""),
                html.H1(id="label1", children=""),
            ]
        ),
    ]
)


@app.callback(
    Output("table", "data"),
    [Input("save", "n_clicks")],
    [State("table", "data")] + [State(column, "value") for column in columns],
)
def update_table(n_clicks, data, *args):
    record = {columns[i]: arg for i, arg in enumerate(list(args))}
    # If the record (identified by user_key) already exists, update it.
    try:
        record_index = [record[user_key] for record in data].index(record[user_key])
        data[record_index] = record
    # Otherwise, append it.
    except ValueError:
        data.append({columns[i]: arg for i, arg in enumerate(list(args))})
    # Return the updated data.
    return data


@app.callback(
    dash.dependencies.Output("label1", "children"),
    [dash.dependencies.Input("interval1", "n_intervals")],
    [dash.dependencies.Input("table", "data")],
)
def use_table(n, data):
    print(type(data))
    if data:
        for dict_item in data:

            print(dict_item["Name"])
            # for key in dict_item:
            #     print (dict_item[key])

            return dict_item["Name"]


if __name__ == "__main__":
    app.run_server()

In brief, The above app allows the user to enter certain values and displays a table below and stores the data entered. I need to display the values(One name at a time, not as a list) retrived in loop from the column Name to the Output component with id lable1. Since adding a return statement in the callback function force exits the ```for loop``, I used a nested callback logic.

1

1 Answers

0
votes

A Dash Input requires a value to be passed to the component_id and component_property parameters.

As the error is telling you, you're only passing one:

missing 1 required positional argument: 'component_property'

Compare the syntax of your inner callback to your outer callback.

Having said all this, don't nest callbacks in the first place. Define callbacks upfront.


Update based on edit

I need to display the values(One name at a time, not as a list) retrived in loop from the column Name to the Output component with id lable1. Since adding a return statement in the callback function force exits the for loop.

You don't need to immediately return something in the loop. You can first build up your list of values and return afterwards. You could initialize a list and append elements to that list when iterating or you could use a list comprehension and do something like this:

@app.callback(
    dash.dependencies.Output("label1", "children"),
    [dash.dependencies.Input("interval1", "n_intervals")],
    [dash.dependencies.Input("table", "data")],
)
def use_table(n, data):
    return ", ".join([dict_item["Name"] for dict_item in data])

This displays all names for every row separated by a comma and a space using a list comprehension, no nested callback needed. Adjust depending on what you want to display.