Dash AG Grid Dynamic Parameters

Hi everyone!

I am trying to create an AG Grid with multiple columns. Two of those columns should have dependent dropdowns, e.g. if I am choosing a country from dropwdown in column “Country”, then in column “City” I should see dropdown containing a list of cities only for that specific country chosen in the previous column.

I found this documentaiton about Dynamic Parameters.

As instructed, I defined this function in dashAgGridFunctions.js file in the assets folder.

var dagfuncs = window.dashAgGridFunctions = window.dashAgGridFunctions || {};

dagfuncs.dynamicOptions = function(params) {
    const selectedCountry = params.data.country;
    if (selectedCountry === 'United States') {
        return {
            values: ['Boston', 'Chicago', 'San Francisco'],
        };
    } else {
        return {
            values: ['Montreal', 'Vancouver', 'Calgary']
        };
    }
}

But this function example is just for two countries.
What if I have dozens of countries with multiple cities for each?

I have a separate file (let’s call it country.py) where I am pulling a dictionary of countries with respective cities and dumping it into a json file.

def sql_cat_json():
    #pulling a df from database and converting it into a dictionary country_dict
    data = [
        {"country": "USA", "city": ["Boston", "NY", "LA"]},
        {"country": "Canada", "city":  ["Montreal", "Vancouver", "Calgary'"]},
        {"country": "Japan", "city": ["Kyoto", "Osaka"]},
        {"country": "Germany", "city": ["Berlin", "Frankfurt", "Hamburg", "Dresden"]}
    ]
    country_json = json.dumps(data, indent=4)
    return country_json

Question 1: How do I send that “country_json” from country.py to the dashAgGridFunctions.js file in the assets folder ?

Question 2: How do I edit the dashAgGridFunctions.js to be really dynamic and show as many countries & cities as in the country_json ?

Thank for all the help in advance.

Hi @mrel

You can pass data to the JavaScript function from your Python app. Here’s an example

dagfuncs.dynamicOptions = function(params, countryData) {
    const country = countryData.find(c => c.country === params.data.country);
    return {
       values: country ? country.city : []
    };
}



import dash_ag_grid as dag
from dash import Dash, html, dcc

app = Dash(__name__)


country_data = [
        {"country": "United States", "city": ["Boston", "NY", "LA"]},
        {"country": "Canada", "city":  ["Montreal", "Vancouver", "Calgary"]},
        {"country": "Japan", "city": ["Kyoto", "Osaka"]},
        {"country": "Germany", "city": ["Berlin", "Frankfurt", "Hamburg", "Dresden"]}
    ]

        

columnDefs = [
    {
        "field": "country",
        "editable": False,
    },
    {
        "headerName": "Select Editor",
        "field": "city",
        "cellEditor": "agSelectCellEditor",
        "cellEditorParams": {
            "function": f"dynamicOptions(params, {country_data})"

        },
    },

]

rowData = [
    {"country": "United States", "city": "Boston"},
    {"country": "Canada", "city": "Montreal"},
    {"country": "Canada", "city": "Vancouver"},
]


app.layout = html.Div(
    [
        dcc.Markdown(
            "This grid has dynamic options for city based on the country.  Try editing the cities."
        ),
        dag.AgGrid(
            id="cell-editor-grid-2",
            columnDefs=columnDefs,
            rowData=rowData,
            columnSize="sizeToFit",
            defaultColDef={"editable": True},
        ),
    ],
    style={"margin": 20},
)


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



2 Likes

Hi @AnnMarieW ,

It doesn’t seem to work as I was hoping.
All it is giving me is two columns: a list of countries in one column and a dropdown in second column.
image

Questions/comments:

  1. I didn’t understand where and how country_json (dictionary converted to json dump) from country.py was used. In the JavaScript I am seeing countryData, not sure what it is. Is it a mistake and it should be country_json ?
  2. You are using rowData in your code which is a different from the country_data that is used in the beginning of your code.
  3. Cells in first column (“Country”) do not have dropdowns.

What I am trying to achieve is to have dropdowns in each cell of each column. User has to choose a country from a dropdown in each cell in the first column. And then has to choose a respective city from dropdown in each cell in the second column.

Hi @mrel

This example was to show how to pass data from your app a JavaScript function.

You could send the country_json to the function but the data is already in json format, so I skipped that step

The JavaScript function in the dashAgGridFunctions.js dynamically updates the dropdown options based on the country. If you would like a dropdown for the country you could add one - and this is simpler because you can just use the data


columnDefs = [
    {
        "field": "country",
        "cellEditor": "agSelectCellEditor",
        "cellEditorParams": {
            "values": [c["country"] for c in data]
        }
    },


Do you want to start with a blank grid? Then you could just have row data that looks something like:


rowData = [{"country": "", "city": ""} for i in range(6)]

Yes, I wanted to start with blank grid.

Ok, let me compile everything I have so far. Right now it is not working. What am I missing ?

Data is coming from json_dump.py file. I need to use this data in dashAgGridFunctions.js and main.py file to create two columns with dropdowns in each cell (countries in first column, cities in second column).

Here is the folder structure.

project/
|   |-- main.py
|   |-- json_dump.py
|   |-- assets/
|   |   |-- dashAgGridFunctions.js

Below is the code I have for all three files.

  1. json_dump.py
import json

def sql_cat_json():
    data = [
                {"country": "USA", "city": ["Boston", "NY", "LA"]},
                {"country": "Canada", "city":  ["Montreal", "Vancouver", "Calgary'"]},
                {"country": "Japan", "city": ["Kyoto", "Osaka"]},
                {"country": "Germany", "city": ["Berlin", "Frankfurt", "Hamburg", "Dresden"]}
        ]
    country_json = json.dumps(data, indent=4)

    return country_json
  1. dashAgGridFunctions.js
var dagfuncs = (window.dashAgGridFunctions = window.dashAgGridFunctions || {});

dagfuncs.dynamicOptions = function (params, country_json) {
  const country = country_json.find((c) => c.country === params.data.country);
  return {
    values: country ? country.city : [],
  };
};
  1. main.py
import dash_ag_grid as dag
from dash import Dash, html, dcc
from json_dump import sql_cat_json

app = Dash(__name__)

columnDefs = [
    {
        "field": "country",
        "cellEditor": "agSelectCellEditor",
        "cellEditorParams": {
            "values": [c["country"] for c in sql_cat_json()]
        }
    },
    {
        "headerName": "Select Editor",
        "field": "city",
        "cellEditor": "agSelectCellEditor",
        "cellEditorParams": {
            "function": f"dynamicOptions(params, {sql_cat_json()})"

        },
    },

]

rowData = [{"country": "", "city": ""} for i in range(6)]

app.layout = html.Div(
    [
        dcc.Markdown(
            "This grid has dynamic options for city based on the country.  Try editing the cities."
        ),
        dag.AgGrid(
            id="cell-editor-grid-2",
            columnDefs=columnDefs,
            rowData=rowData,
            columnSize="sizeToFit",
            defaultColDef={"editable": True},
        ),
    ],
    style={"margin": 20},
)


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

Hi @mrel

The error is likely in the list of countries. For debugging try this:

countries = [c["country"] for c in sql_cat_json()]
print(countries)

Your function returns a json formated string. In order for the above to work, you would have to turn it back into a python object with json.loads().

Here’s one solution - make the sql_cat_json function return the list of countries to use in the dropdown of countries column, and the country_json to use for the options in the city dropdown.

def sql_cat_json():
    data = [
                {"country": "USA", "city": ["Boston", "NY", "LA"]},
                {"country": "Canada", "city":  ["Montreal", "Vancouver", "Calgary'"]},
                {"country": "Japan", "city": ["Kyoto", "Osaka"]},
                {"country": "Germany", "city": ["Berlin", "Frankfurt", "Hamburg", "Dresden"]}
        ]
    country_json = json.dumps(data, indent=4)
    countries =  [c["country"] for c in data]
    return country_json, countries

import dash_ag_grid as dag
from dash import Dash, html, dcc
from json_dump import sql_cat_json

app = Dash(__name__)

country_json, countries = sql_cat_json()

columnDefs = [
    {
        "field": "country",
        "cellEditor": "agSelectCellEditor",
        "cellEditorParams": {
            "values": countries
        }

    },
    {
        "headerName": "Select Editor",
        "field": "city",
        "cellEditor": "agSelectCellEditor",
        "cellEditorParams": {
            "function": f"dynamicOptions2(params, {country_json})"

        },
    },
]

rowData = [{"country": "", "city": ""} for i in range(6)]


app.layout = html.Div(
    [
        dcc.Markdown(
            "This grid has dynamic options for city based on the country.  Try editing the cities."
        ),
        dag.AgGrid(
            id="cell-editor-grid-2",
            columnDefs=columnDefs,
            rowData=rowData,
            columnSize="sizeToFit",
            defaultColDef={"editable": True},
        ),
    ],
    style={"margin": 20},
)


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


2 Likes

Worked perfectly.
Thank you so much, @AnnMarieW !

Hey Everyone,

I’m trying to accomplish the same thing and it’s not working for me as expected.

I’m trying to figure out what I’m doing wrong.

For a “Category” column, I want to show a dropdown with elements passed in from the python code.

I’m doing this:

if i == ‘Category’:
entry[‘editable’] = True
entry[‘cellEditor’] = {“function”: “DCC_Dropdown”}
entry[‘cellEditorParams’] = {“function”: “dynamicOptionsFromParams(params, {categoryOptions})”}
entry[‘cellEditorPopup’] = True
entry[‘cellEditorPopupPosition’] = ‘under’

My categoryOptions JSON looks like this:
‘[{“label”: “AWEP GI cut-in”, “value”: “AWEP GI cut-in”}, {“label”: “Case cut-in”, “value”: “Case cut-in”}]’

(I’ve also tried just passing a straight list object - without converting to JSON)

My js code in dashAgGridFunctions.js looks like this:
dagfuncs.dynamicOptionsFromParams = function(params, options) {
return {
values: [‘True’, ‘False’],
};
}

I’m just trying to catch this in the debugger to see what options looks like.

I don’t get any errors when I run, but my breakpoint (in Chrome console) never catches and my dropdown is empty.

However, if I remove the options parameter (in the python and javascript) it works as expected.

What am I missing?

Thanks in advance!