Dash-ag-grid comparator - "Uncaught TypeError: g is not a function"

Hey,
I am using dash-ag-grid (community) version 31.0.1.

I have a table which some of its cells contain a dictionary object instead of a string/number. In the dictionary, one of the fields is called ‘label’ which contains the value I want to show (the other fields in the dict are for me to process when a user clicks on the table, to do some custom actions).

Because the cell contains a dictionary, I cannot use the default sort mechanism, but to activate a custom sorting, by passing a comparator function, implemented in js.

I have implemented a js file called dashAgGridComponentFunctions.js under the assets directory of my app, and initialized it, this is basically how it looks:

var dagcomponentfuncs = (window.dashAgGridComponentFunctions = window.dashAgGridComponentFunctions || {});

dagcomponentfuncs.ActionRenderWithLabel = function (props) {
    if (!props.hasOwnProperty('value') || props.value == null) {
        return React.createElement('div', {}, "")
    }
    else {
        if (props.value.hasOwnProperty('tooltip')){
            const tooltip_hash = `tooltip_${hashCode(props.value.tooltip)}`
            info = [
                React.createElement('div', {}, props.value.tooltip),
            ];
            return React.createElement('a',{}, [
                    React.createElement(
                        window.dash_bootstrap_components.Tooltip,
                        {
                            target: tooltip_hash,
                            placement: 'bottom'
                        },
                        info
                    ),
                    React.createElement(
                        "div",
                        {
                            id: tooltip_hash,
                            href: '#'
                        },
                        props.value.label
                    )
                ]
            )
        } else {
            return React.createElement(
                "a",
                {
                    id: props.value.label,
                    href: '#'
                },
                props.value.label
            )
        }
    }
};

dagcomponentfuncs.LabelComparator = function (valueA, valueB, nodeA, nodeB, isDescending) {
    let labelA = valueA && valueA.label ? valueA.label : "";
    let labelB = valueB && valueB.label ? valueB.label : "";
    if (parseInt(labelA) == parseInt(labelB)) return 0;
    return (parseInt(labelA) > parseInt(labelB)) ? 1 : -1;
};

In my ag grid table, at the column def, I pass to the cell the following funcs:
cellRenderer: ActionRenderWithLabel
comparator: LabelComparator

You can view the code below:

definition:

MODEL_TABLE_COLUMN_DEFS = [
    {"field": "model_id", "headerName": "Model", "checkboxSelection": True,
     'cellRenderer': 'ActionRenderWithLabel', 'comparator': 'LabelComparator',
     'filter': 'agNumberColumnFilter', 'sortingOrder': ['desc', 'asc', None]},
    {"field": "build_id", "headerName": "Build", 'cellDataType': 'number', 'filter': 'agNumberColumnFilter'},
    ...
]
...
DEFAULT_COLUMN_DEFINITION = {'filter': false}
...
MODEL_GRID = dag.AgGrid(
    className="ag-theme-alpine-dark",
    id='model_table',
    columnDefs=MODEL_TABLE_COLUMN_DEFS,
    columnSize="sizeToFit",
    defaultColDef=DEFAULT_COLUMN_DEFINITION,
    style={"height": "20vh"},
    persistence=False,
    csvExportParams={"fileName": "model_summary.csv"},
    dashGridOptions={"rowSelection": "single", "suppressRowClickSelection": True, "animateRows": False, "enableCellTextSelection": True}
)

rows insertion:

for model_entry in model_entries:
    build_entries = None
    base_data = dict(model_id=dict(label=model_entry.id, tooltip=model_entry.notes, action='open_tab',  tab_name=f'model__{model_entry.id}'),  build_id=None, ...)
    data.append(base_data)

I can see that the cell renderer works correctly, as it shows the label I intended to show, but the comparator would raise this error in the console:

Uncaught TypeError: g is not a function
at t.compareRowNodes (ag-grid-community.auto.esm.js:51217:36)
at Array.sort ()
at t.doFullSort (ag-grid-community.auto.esm.js:51201:24)
at ag-grid-community.auto.esm.js:57253:65
at e.depthFirstSearchEverything (ag-grid-community.auto.esm.js:41015:9)
at e.forEachChangedNodeDepthFirst (ag-grid-community.auto.esm.js:41029:18)
at t.sort (ag-grid-community.auto.esm.js:57265:25)
at t.execute (ag-grid-community.auto.esm.js:57020:26)
at t.doSort (ag-grid-community.auto.esm.js:56633:24)
at t.refreshModel (ag-grid-community.auto.esm.js:56336:22)

What I tried:
I tried to change the definition of the comparator to be:
comparator: {function: LabelComparator}
But it did not solve it either and did not call my function. (Although the renderer is being called ok).

I also tried to pass the function as an annonymus function directly and it did not work.

P.s. When I debugged the code (ag-grid-community.js) with chrome devtools, I saw that it retrieves the function name and then tries to call it using the string it got, which is quite odd for me…

I am clueless of how to solve this, and would appreciate any help.

Thanks!

Hello @Ariele,

Welcome to the community!

According to the documents, you should be using this:

You should also be using the most recent version, which is 31.3.0. :slight_smile:

Hey, thank you for your response!
I have upgraded my dash version to 31.3.0 and made sure I am using it the way it shows in the documentation, but it still not work, seems like it is ignoring my function.

My code:

cell definition:

MODEL_TABLE_COLUMN_DEFS = [
{"field": "model_id", "headerName": "Model", "checkboxSelection": True,
     'cellRenderer': 'ActionRenderWithLabel', 'comparator': {'function': 'LabelComparator'},
     'filter': 'agNumberColumnFilter', 'sortingOrder': ['desc', 'asc', None]}
...
]

Grid definition:

MODEL_GRID = dag.AgGrid(
    className="ag-theme-alpine-dark",
    id='model_table',
    columnDefs=MODEL_TABLE_COLUMN_DEFS,
    columnSize="sizeToFit",
    defaultColDef=DEFAULT_COLUMN_DEFINITION,
    style={"height": "20vh"},
    persistence=False,
    csvExportParams={"fileName": "model_summary.csv"},
    dashGridOptions={"rowSelection": "single", "suppressRowClickSelection": True, "animateRows": False,
                     "enableCellTextSelection": True}
)

Js code, exists under assets directory + I can see that the function exists in the scop by console logging it.

I just changed the function to be exactly as in the example you sent me:

dagcomponentfuncs.LabelComparator = function (valueA, valueB) {
    console.log('Inside comparator');
    let labelA = valueA && valueA.label ? valueA.label : "";
    let labelB = valueB && valueB.label ? valueB.label : "";
    if (parseInt(labelA) == parseInt(labelB)) return 0;
    return (parseInt(labelA) > parseInt(labelB)) ? 1 : -1;
};

JS code is the same as I posted on top. The weird thing is that the Renderer function works as expected, so why would the comparator won’t?

insertion of data is the same as in my first post.

No one else encountered this issue?

Edit:
After debugging through the main.esn.mjs code using the chrome debugger devtool, I can see that the comparator passed to the userColDef oh the model_id column has: comparator: undefined. I am guessing it cannot find the function? why is that? Should I put something else in my code for the dash app to notice the js file I wrote?

Edit2:
I found the solution -
I used a wrong scope for the comparator function. it should be under:
window.dashAgGridFunctions

and not:
window.dashAgGridComponentFunctions

1 Like