# Dash AG Grid async options

**URL:** <https://community.plotly.com/t/dash-ag-grid-async-options/79970>\
**Category:** Dash Python\
**Tags:** question\
**Created:** [November 8, 2023, 10:37pm UTC](https://community.plotly.com/t/dash-ag-grid-async-options/79970 "2023-11-08T22:37:27Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![aKib](https://avatars.discourse-cdn.com/v4/letter/a/f4b2a3/32.png) [@aKib](https://community.plotly.com/u/aKib)\
**Post date:** [November 8, 2023, 10:37pm UTC](https://community.plotly.com/t/dash-ag-grid-async-options/79970/1 "2023-11-08T22:37:27Z")

</div>

hi there, i am trying to update options for either dcc dropdown or dmc select within an ag grid cell for a column

columnDefs = [  
{  
“field”: “column1”,  
“editable”: True,  
“checkboxSelection”: True,  
“cellEditor”: {“function”: “DCC\_Dropdown”},  
# “cellEditor”: {“function”: “DMC\_Select”},  
“cellEditorPopup”: True,  
“filter”: True,  
}]

I’ve taken a look at both DCC\_Dropdown and DMC\_Select in the plotly ag grid github and tried to define a async function called updateOptions() that takes in the searchvalue and gets a return json and sets this.options but the component doesnt rerender upon this.options having new data. I am unfortunately not super familiar with javascript/react and was wondering if someone could take a look.

I tried modifying cellEditorParams to be {“values”: “updateOptions(params)”) as that works in this sandbox i was testing out ([Plunker - Dynamic Parameters](https://plnkr.co/edit/DEwB5a6Lh7juXsjY?open=main.js)) but within my dash app the function doesnt even seem to be called.

- getGenders() is an async function that returns [‘Male’, ‘Female’] after a timeout. I tried to do something similar in dash ag grid’s celleditorparams and it didnt work

im using :

dash 2.13.0  
dash-mantine-components 0.12.1  
dash-ag-grid 2.4.0

and both DMC\_Select and DCC\_Dropdown im using are in  
[https://github.com/plotly/dash-ag-grid/blob/c12fc22e1278b09afeeb4a5ae5c4e3bbbebb35f6/docs/examples/components/assets/dashAgGridFunctions.js#L259](https://github.com/plotly/dash-ag-grid/blob/c12fc22e1278b09afeeb4a5ae5c4e3bbbebb35f6/docs/examples/components/assets/dashAgGridFunctions.js#L259)

---

<div class="post-metadata">

**Author:** ![jinnyzor](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/jinnyzor/32/21194_2.png) [@jinnyzor](https://community.plotly.com/u/jinnyzor)\
**Post date:** [November 9, 2023, 10:34am UTC](https://community.plotly.com/t/dash-ag-grid-async-options/79970/2 "2023-11-09T10:34:42Z")

</div>

Hello @aKib,

Welcome to the community!

You are trying to provide options based upon an async function/server call?

You can check out this topic here for how I was able to do this:

> [@Dash AgGrid : Dynamic Cell Dropdown Options (from server callback)](https://community.plotly.com/t/dash-aggrid-dynamic-cell-dropdown-options-from-server-callback/79633/3):
>
> Hello @popo, This isnt exactly a walk in the park, it uses quite a bit of advanced knowledge of flask, JS and the grid: app.py: import random, json import dash from dash import Dash, html, dcc, Input, Output, State, Patch, ctx, MATCH, ALL import dash\_ag\_grid as dag from flask import jsonify, request import dash\_mantine\_components app = Dash(\_\_name\_\_) columnDefs = [ {"field": "A"}, { "field": "dynamic\_select", "editable": True, "cellEditor": {'function': "DMC\_…

If you want to, you can also make `cellEditorParams` a whole function and return the data however you want using JS functions, etc.

---

<div class="post-metadata">

**Author:** ![aKib](https://avatars.discourse-cdn.com/v4/letter/a/f4b2a3/32.png) [@aKib](https://community.plotly.com/u/aKib)\
**Post date:** [November 9, 2023, 4:12pm UTC](https://community.plotly.com/t/dash-ag-grid-async-options/79970/3 "2023-11-09T16:12:07Z")

</div>

Hi @jinnyzor ,

Thank you for the welcome! Yes, I am trying to provide options based on async function/server call based on search value, how would I achieve that ? Within setProps I could set this.search\_value to be whats the component passes back, but how would i initiate the componenet rerender on each search value change?

```auto
var setProps = (props) => {
            if (typeof props.value != typeof undefined) {
                // updates the value of the editor
                this.value = props.value;

                // re-enables keyboard event
                delete params.colDef.suppressKeyboardEvent;

                // tells the grid to stop editing the cell
                params.api.stopEditing();

                // sets focus back to the grid's previously active cell
                this.prevFocus.focus();

            }
            if (props.search_value !== '') {
                this.search_value = props.search_value;
            }
        };

//something akin to this?
dropdownRequest(this.search_value).then((data) => { ... });
```

---

<div class="post-metadata">

**Author:** ![jinnyzor](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/jinnyzor/32/21194_2.png) [@jinnyzor](https://community.plotly.com/u/jinnyzor)\
**Post date:** [November 9, 2023, 5:03pm UTC](https://community.plotly.com/t/dash-ag-grid-async-options/79970/4 "2023-11-09T17:03:06Z")

</div>

For this, you could possibly use something like `useEffect` on the `this.search_value` and force it to rerender.

Give me a bit and I might be able to come up with something to allow you some options.

Do you have a small example app I can try on?

---

<div class="post-metadata">

**Author:** ![aKib](https://avatars.discourse-cdn.com/v4/letter/a/f4b2a3/32.png) [@aKib](https://community.plotly.com/u/aKib)\
**Post date:** [November 9, 2023, 6:43pm UTC](https://community.plotly.com/t/dash-ag-grid-async-options/79970/5 "2023-11-09T18:43:24Z")

</div>

a small example app could be something like this (sorry for the bareness, scraped something togheter)

app.py

```py

import dash
from dash import html, dcc
import pandas as pd
from dash.dependencies import Input, Output
import dash_ag_grid as dag
import dash_mantine_components as dmc

# Create a DataFrame
df = pd.DataFrame({
    'Name': ['Person' + str(i) for i in range(20)],
    'favorite_word': ["" for _ in range(20)],
})

# Initialize the Dash app
app = dash.Dash( __name__ )

# Define the layout of the app
app.layout = html.Div([
    dag.AgGrid(
        id='table',
        rowData=df.to_dict('records'),
        columnDefs=[{"headerName": i, "field": i,
                     "cellEditor": {"function": "DMC_Select"},
                     "editable": True,
                     "cellEditorParams": {"creatable": True, "searchable": True},
                        "cellEditorPopup": True,
                     } for i in df.columns],
        defaultColDef={'flex': 1},
    )
])

# Run the app
if __name__ == ' __main__':
    app.run_server(debug=True, port=8080)

```

dashAgGridFunctions.js

```js

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

const [useRef, useState, Component, forwardRef] = [React.useRef, React.useState, React.Component, React.forwardRef]

dagfuncs.dynamicOptions = async function (search) {

    try {
        let response = await fetch(`https://random-word-form.repl.co/random/noun/${search}?count=10`, {
            method: "GET",
            credentials: "include",
            headers: {
                "Content-Type": "application/json",
            }
        });
        if (!response.ok) {
            console.log(`HTTP error: ${response.status}`);
        }
        const responseData = await response.json();
        return responseData;
    } catch (e) {
        console.log(e);
    }
}

//... DMC Select the same as before

```

---

<div class="post-metadata">

**Author:** ![jinnyzor](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/jinnyzor/32/21194_2.png) [@jinnyzor](https://community.plotly.com/u/jinnyzor)\
**Post date:** [November 9, 2023, 6:44pm UTC](https://community.plotly.com/t/dash-ag-grid-async-options/79970/6 "2023-11-09T18:44:36Z")

</div>

Hey @aKib,

If you are trying to limit search results, you do know that dmc can do this natively?

I’m not exactly sure about this use-case for tying it to the searchValue… XD

---

<div class="post-metadata">

**Author:** ![aKib](https://avatars.discourse-cdn.com/v4/letter/a/f4b2a3/32.png) [@aKib](https://community.plotly.com/u/aKib)\
**Post date:** [November 9, 2023, 6:53pm UTC](https://community.plotly.com/t/dash-ag-grid-async-options/79970/7 "2023-11-09T18:53:25Z")

</div>

ah sorry, i was trying to give an example as the endpoint im reaching is internal, the workflow is basically like theres a total number of values i can get \> 200k, therefore upon search\_value change, it sends the search value to another endpoint and gets back json of the filtered results for me (no filtering done on the dash app)

---

<div class="post-metadata">

**Author:** ![jinnyzor](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/jinnyzor/32/21194_2.png) [@jinnyzor](https://community.plotly.com/u/jinnyzor)\
**Post date:** [November 9, 2023, 6:57pm UTC](https://community.plotly.com/t/dash-ag-grid-async-options/79970/8 "2023-11-09T18:57:41Z")

</div>

Ah, ok.

Wanted to make there there wasnt already a way to accomplish this without performing a call like this. 😉

---

<div class="post-metadata">

**Author:** ![jinnyzor](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/jinnyzor/32/21194_2.png) [@jinnyzor](https://community.plotly.com/u/jinnyzor)\
**Post date:** [November 9, 2023, 7:29pm UTC](https://community.plotly.com/t/dash-ag-grid-async-options/79970/9 "2023-11-09T19:29:32Z")

</div>

This should get you started:

```auto
dynamicOptions = async function (search) {
    try {
        let response = await fetch('./dynamicOptions', {method: 'POST', headers: {'content-type': 'application/json'}, body: JSON.stringify({'searchValue':search})})
        if (!response.ok) {
            console.log(`HTTP error: ${response.status}`);
        }
        const responseData = await response.json();
        return responseData;
    } catch (e) {
        console.log(e);
    }
}

dagfuncs.DMC_Select2 = class {

    // gets called once before the renderer is used
    init(params) {
        var options = [];

        // create the cell
        this.params = params;

        // function for when Dash is trying to send props back to the component / server
        var setProps = (props) => {
            if (typeof props.value != typeof undefined) {
                // updates the value of the editor
                this.value = props.value;

                // re-enables keyboard event
                delete params.colDef.suppressKeyboardEvent;

                // tells the grid to stop editing the cell
                params.api.stopEditing();

                // sets focus back to the grid's previously active cell
                this.prevFocus.focus();
            }
            if (typeof props.searchValue != typeof undefined) {
                dynamicOptions(props.searchValue).then((opts) =>
                    ReactDOM.render(
                        React.createElement(window.dash_mantine_components.Select, {
                            data: opts,
                            value: params.value,
                            setProps,
                            style: {width: params.column.actualWidth-2, ...params.style},
                            className: params.className,
                            clearable: params.clearable,
                            searchable: params.searchable || true,
                            creatable: params.creatable,
                            debounce: params.debounce,
                            disabled: params.disabled,
                            filterDataOnExactSearchMatch:
                                params.filterDataOnExactSearchMatch,
                            limit: params.limit,
                            maxDropdownHeight: params.maxDropdownHeight,
                            nothingFound: params.nothingFound,
                            placeholder: params.placeholder,
                            required: params.required,
                            searchValue: params.searchValue,
                            shadow: params.shadow,
                            size: params.size,
                            styles: params.styles,
                            switchDirectionOnFlip: params.switchDirectionOnFlip,
                            variant: params.variant,
                        }),
                        this.eInput
                        )
                )
            }
        };
        this.eInput = document.createElement('div');

        ReactDOM.render(
        React.createElement(window.dash_mantine_components.Select, {
            data: options,
            value: params.value,
            setProps,
            style: {width: params.column.actualWidth-2, ...params.style},
            className: params.className,
            clearable: params.clearable,
            searchable: params.searchable || true,
            creatable: params.creatable,
            debounce: params.debounce,
            disabled: params.disabled,
            filterDataOnExactSearchMatch:
                params.filterDataOnExactSearchMatch,
            limit: params.limit,
            maxDropdownHeight: params.maxDropdownHeight,
            nothingFound: params.nothingFound,
            placeholder: params.placeholder,
            required: params.required,
            searchValue: params.searchValue,
            shadow: params.shadow,
            size: params.size,
            styles: params.styles,
            switchDirectionOnFlip: params.switchDirectionOnFlip,
            variant: params.variant,
        }),
        this.eInput
        )

        // allows focus event
        this.eInput.tabIndex = '0';

        // sets editor value to the value from the cell
        this.value = params.value;
    }

    // gets called once when grid ready to insert the element
    getGui() {
        return this.eInput;
    }

    focusChild() {
        // needed to delay and allow the component to render
        setTimeout(() => {
            var inp = this.eInput.getElementsByClassName(
                'mantine-Select-input'
            )[0];
            inp.tabIndex = '1';

            // disables keyboard event
            this.params.colDef.suppressKeyboardEvent = (params) => {
                const gridShouldDoNothing = params.editing;
                return gridShouldDoNothing;
            };
            // shows dropdown options
            inp.focus();
        }, 100);
    }

    // focus and select can be done after the gui is attached
    afterGuiAttached() {
        // stores the active cell
        this.prevFocus = document.activeElement;

        // adds event listener to trigger event to go into dash component
        this.eInput.addEventListener('focus', this.focusChild());

        // triggers focus event
        this.eInput.focus();
    }

    // returns the new value after editing
    getValue() {
        return this.value;
    }

    // any cleanup we need to be done here
    destroy() {
        // sets focus back to the grid's previously active cell
        this.prevFocus.focus();
    }
};

```

```auto
import dash
from dash import html, dcc
import pandas as pd
from dash.dependencies import Input, Output
import dash_ag_grid as dag
import dash_mantine_components as dmc
import requests
from flask import request

# Create a DataFrame
df = pd.DataFrame({
    'Name': ['Person' + str(i) for i in range(20)],
    'favorite_word': ["" for _ in range(20)],
})

# Initialize the Dash app
app = dash.Dash( __name__ )

# Define the layout of the app
app.layout = html.Div([
    dag.AgGrid(
        id='table',
        rowData=df.to_dict('records'),
        columnDefs=[{"headerName": i, "field": i,
                     "cellEditor": {"function": "DMC_Select2"},
                     "editable": True,
                     "cellEditorParams": {"creatable": True, "searchable": True},
                        "cellEditorPopup": True,
                     } for i in df.columns],
        defaultColDef={'flex': 1},
    )
])

@app.server.route('/dynamicOptions', methods=['POST'])
def dynamicOptions():
    try:
        url = f'https://random-word-form.repl.co/random/noun/{request.json.get("searchValue")}?count=10'
        resp = requests.get(url).json()
        return resp
    except:
        return []

# Run the app
if __name__ == ' __main__':
    app.run_server(debug=True, port=8080)

```

---

<div class="post-metadata">

**Author:** ![aKib](https://avatars.discourse-cdn.com/v4/letter/a/f4b2a3/32.png) [@aKib](https://community.plotly.com/u/aKib)\
**Post date:** [November 9, 2023, 10:11pm UTC](https://community.plotly.com/t/dash-ag-grid-async-options/79970/10 "2023-11-09T22:11:17Z")

</div>

ohhh so the secret sauce was to rerender it within set props. Amazing, thank you so much!

---

<div class="post-metadata">

**Author:** ![jinnyzor](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/jinnyzor/32/21194_2.png) [@jinnyzor](https://community.plotly.com/u/jinnyzor)\
**Post date:** [November 9, 2023, 10:21pm UTC](https://community.plotly.com/t/dash-ag-grid-async-options/79970/11 "2023-11-09T22:21:06Z")

</div>

Correct, the useEffect wasn’t working in this case. They work when using the forwardRef method, not the class.
