Hi. Help to fix error Cannot read properties of undefined (reading 'Spinner')
. I want to reproduce logic of https://dash.plotly.com/dash-ag-grid/infinite-row-model#specify-selectable-rows with spinner. Example 2: Equal Pagination Page Size and Large Infinite Block Size.
Hello @AlesiaSel,
Without seeing your code, its hard to tell where your code is going wrong.
My guess is that you dont have the dbc importing into your app.
#dag-docs
@jinnyzor I tried to run code from dash
import dash_ag_grid as dag
from dash import Dash, Input, Output, html, no_update, callback
import pandas as pd
import time
app = Dash(__name__)
df = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)
columnDefs = [
# this row shows the row index, doesn't use any data from the row
{
"headerName": "ID",
"maxWidth": 100,
# it is important to have node.id here, so that when the id changes (which happens
# when the row is loaded) then the cell is refreshed.
"valueGetter": {"function": "params.node.id"},
"cellRenderer": "SpinnerCellRenderer",
},
{"field": "athlete", "minWidth": 150},
{"field": "country", "minWidth": 150},
{"field": "year"},
{"field": "sport", "minWidth": 150},
{"field": "total"},
]
defaultColDef = {
"flex": 1,
"minWidth": 150,
"sortable": False,
"resizable": True,
}
app.layout = html.Div(
[
dag.AgGrid(
id="infinite-row-model-pagination",
columnDefs=columnDefs,
defaultColDef=defaultColDef,
rowModelType="infinite",
dashGridOptions={
# The number of rows rendered outside the viewable area the grid renders.
"rowBuffer": 0,
# How many blocks to keep in the store. Default is no limit, so every requested block is kept.
"maxBlocksInCache": 2,
"cacheBlockSize": 100,
"cacheOverflowSize": 2,
"maxConcurrentDatasourceRequests": 2,
"infiniteInitialRowCount": 1,
"rowSelection": "multiple",
"pagination": True,
},
),
],
)
@callback(
Output("infinite-row-model-pagination", "getRowsResponse"),
Input("infinite-row-model-pagination", "getRowsRequest"),
)
def infinite_scroll(request):
# simulate slow callback
time.sleep(2)
if request is None:
return no_update
partial = df.iloc[request["startRow"]: request["endRow"]]
return {"rowData": partial.to_dict("records"), "rowCount": len(df.index)}
if __name__ == "__main__":
app.run(debug=True)
Example 2: Equal Pagination Page Size and Large Infinite Block Size
here js file too
structure of folders:
-assets/
----css/
----js/
--------this js file
-app.py
I’m not very good at js, so I need help.
import dash_ag_grid as dag
from dash import Dash, Input, Output, html, no_update, callback
import pandas as pd
import time
import dash_bootstrap_components as dbc
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
df = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)
columnDefs = [
# this row shows the row index, doesn't use any data from the row
{
"headerName": "ID",
"maxWidth": 100,
# it is important to have node.id here, so that when the id changes (which happens
# when the row is loaded) then the cell is refreshed.
"valueGetter": {"function": "params.node.id"},
"cellRenderer": "SpinnerCellRenderer",
},
{"field": "athlete", "minWidth": 150},
{"field": "country", "minWidth": 150},
{"field": "year"},
{"field": "sport", "minWidth": 150},
{"field": "total"},
]
defaultColDef = {
"flex": 1,
"minWidth": 150,
"sortable": False,
"resizable": True,
}
app.layout = html.Div(
[
dag.AgGrid(
id="infinite-row-model-pagination",
columnDefs=columnDefs,
defaultColDef=defaultColDef,
rowModelType="infinite",
dashGridOptions={
# The number of rows rendered outside the viewable area the grid renders.
"rowBuffer": 0,
# How many blocks to keep in the store. Default is no limit, so every requested block is kept.
"maxBlocksInCache": 2,
"cacheBlockSize": 100,
"cacheOverflowSize": 2,
"maxConcurrentDatasourceRequests": 2,
"infiniteInitialRowCount": 1,
"rowSelection": "multiple",
"pagination": True,
},
),
],
)
@callback(
Output("infinite-row-model-pagination", "getRowsResponse"),
Input("infinite-row-model-pagination", "getRowsRequest"),
)
def infinite_scroll(request):
# simulate slow callback
time.sleep(2)
if request is None:
return no_update
partial = df.iloc[request["startRow"]: request["endRow"]]
return {"rowData": partial.to_dict("records"), "rowCount": len(df.index)}
if __name__ == "__main__":
app.run(debug=True)
Hi @AlesiaSel
Thanks for asking the question! I’ll do a PR to fix the docs.
Even if you don’t use dash_bootstrap_components
anywhere else in your app, it’s necessary for the SpinnerCellRenderer
component , so it’s necessary to add:
import dash_bootstrap_components as dbc
and to add the Bootstrap stylesheet in the app constructor:
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
Be sure that you are importing dash_bootstrap_components as well.
i copy-paste your code and run
import dash_ag_grid as dag
from dash import Dash, Input, Output, html, no_update, callback
import pandas as pd
import time
import dash_bootstrap_components as dbc
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
df = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)
columnDefs = [
# this row shows the row index, doesn't use any data from the row
{
"headerName": "ID",
"maxWidth": 100,
# it is important to have node.id here, so that when the id changes (which happens
# when the row is loaded) then the cell is refreshed.
"valueGetter": {"function": "params.node.id"},
"cellRenderer": "SpinnerCellRenderer",
},
{"field": "athlete", "minWidth": 150},
{"field": "country", "minWidth": 150},
{"field": "year"},
{"field": "sport", "minWidth": 150},
{"field": "total"},
]
defaultColDef = {
"flex": 1,
"minWidth": 150,
"sortable": False,
"resizable": True,
}
app.layout = html.Div(
[
dag.AgGrid(
id="infinite-row-model-pagination",
columnDefs=columnDefs,
defaultColDef=defaultColDef,
rowModelType="infinite",
dashGridOptions={
# The number of rows rendered outside the viewable area the grid renders.
"rowBuffer": 0,
# How many blocks to keep in the store. Default is no limit, so every requested block is kept.
"maxBlocksInCache": 2,
"cacheBlockSize": 100,
"cacheOverflowSize": 2,
"maxConcurrentDatasourceRequests": 2,
"infiniteInitialRowCount": 1,
"rowSelection": "multiple",
"pagination": True,
},
),
],
)
@callback(
Output("infinite-row-model-pagination", "getRowsResponse"),
Input("infinite-row-model-pagination", "getRowsRequest"),
)
def infinite_scroll(request):
# simulate slow callback
time.sleep(2)
if request is None:
return no_update
partial = df.iloc[request["startRow"]: request["endRow"]]
return {"rowData": partial.to_dict("records"), "rowCount": len(df.index)}
if __name__ == "__main__":
app.run(debug=True)
assets/js/dashAgGridComponentFunctions.js:
its not work for me.
does it work for you?
Ooooohhhhh.
Upgrade your dash version to 2.16.1.
There was an issue with importing unused libraries into the apps window initially.
Also, as another note, we are on ag grid v31 now.
Hi. Yep. It works with dash==2.16.1, not dash==2.16.0. But when the page is initially loaded, I encounter the following
which was not the case in 2.16.0
is it possible to fix it somehow?
Thanks
This is something to do with hot reloading, you should be able to ignore for now.
Please, help me figure out 1 more point. this is a minimal reproducible example of my app in which I use a spinner
import dash
from dash import dcc, html, ctx, no_update, callback, Input, Output, State
import pandas as pd
import dash_mantine_components as dmc
import dash_ag_grid as dag
from dash.exceptions import PreventUpdate
import plotly.express as px
import dash_bootstrap_components as dbc
df = px.data.gapminder()
data = {'df': df}
external_stylesheets=[dbc.themes.BOOTSTRAP]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
COLUMNS = ['ID', 'country', 'continent', 'year', 'lifeExp', 'pop', 'gdpPercap', 'iso_alpha', 'iso_num']
def generate_default_col_defs(columns=COLUMNS):
columnDefs=[
{'headerName': col, 'field': col, 'minWidth': 150, 'maxWidth': 150, 'width': 150} for col in columns
]
return columnDefs
def generate_col_defs(columns=COLUMNS):
columnDefs=[
{'headerName': col, 'field': col, 'minWidth': 150, 'maxWidth': 150, 'width': 150,
"valueFormatter": {"function": "params.value ? (params.value.toFixed(2)) : null"}} if col=='lifeExp'
else {"headerName": col, 'field': col, 'minWidth': 100, 'maxWidth': 100, 'width': 100, 'pinned': 'left',
"valueGetter": {"function": "params.node.id"}, "cellRenderer": "SpinnerCellRenderer",
}
if col == 'ID'
else {'headerName': col, 'field': col, 'minWidth': 150, 'maxWidth': 150, 'width': 150} for col in columns
]
return columnDefs
app.layout = dmc.MantineProvider(
children=html.Div(
children=[
dmc.Group(
children=[
dcc.Dropdown(
id='dropdown',
options=[
{'label': 'data1.csv', 'value': 'df'},
],
placeholder='Choose CSV'
),
dmc.Button('Load data', id='load-button', n_clicks=0),
],
),
html.Div(
children=[
dag.AgGrid(
id='infinite-grid',
rowModelType="infinite",
columnDefs=generate_default_col_defs(),
columnSize="autoSize",
defaultColDef={'resizable': True, 'editable': False, 'sortable': True},
dashGridOptions={"rowBuffer": 0,
"maxBlocksInCache": 2,
"cacheBlockSize": 100,
"cacheOverflowSize": 2,
"maxConcurrentDatasourceRequests": 2,
"infiniteInitialRowCount": 1,
"pagination": True},
),
],
),
],
),
)
@callback(
output=[
Output('infinite-grid', "getRowsResponse"),
Output('infinite-grid', 'paginationGoTo'),
Output('infinite-grid', "columnDefs"),
],
inputs=[
Input('load-button', "n_clicks"),
Input('infinite-grid', "getRowsRequest"),
],
state=[
State('dropdown', "value"),
],
running=[
(Output('load-button', "disabled"), True, False),
],
# background=True,
prevent_initial_call=True
)
def update_layout(n_clicks, request, value):
if value:
dff = data.get(value).copy()
dff.insert(0, 'ID', dff.index)
if 'load-button' == ctx.triggered_id:
partial = dff.to_dict('records')[0:100]
response = {"rowData": partial, "rowCount": len(dff)}
return response, 0, generate_col_defs()
elif request:
partial = dff.to_dict('records')[request["startRow"]:request["endRow"]]
response = {"rowData": partial, "rowCount": len(dff)}
return response, no_update, generate_col_defs()
raise PreventUpdate
if __name__ == '__main__':
app.run_server(debug=True)
I need this realization.
When the data is initially loaded into the grid - spinner, it does not work. Only when switching between pages. Why is this happening and what needs to be changed so that the spinner appears when the button is pressed. Thanks
Here is a version that should work for what you want to do:
import dash
from dash import dcc, html, ctx, no_update, callback, Input, Output, State
import pandas as pd
import dash_mantine_components as dmc
import dash_ag_grid as dag
from dash.exceptions import PreventUpdate
import plotly.express as px
import dash_bootstrap_components as dbc
import time
df = px.data.gapminder()
data = {'df': df}
external_stylesheets=[dbc.themes.BOOTSTRAP]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
COLUMNS = ['ID', 'country', 'continent', 'year', 'lifeExp', 'pop', 'gdpPercap', 'iso_alpha', 'iso_num']
def generate_default_col_defs(columns=COLUMNS):
columnDefs=[
{'field': col} for col in columns
]
return columnDefs
def generate_col_defs(columns=COLUMNS):
columnDefs=[
{'field': col,
"valueFormatter": {"function": "params.value ? (params.value.toFixed(2)) : null"}} if col=='lifeExp'
else {'field': col, 'pinned': 'left',
"valueGetter": {"function": "params.node.id"}, "cellRenderer": "SpinnerCellRenderer",
}
if col == 'ID'
else {'field': col} for col in columns
]
return columnDefs
app.layout = dmc.MantineProvider(
children=html.Div(
children=[
dmc.Group(
children=[
dcc.Dropdown(
id='dropdown',
options=[
{'label': 'data1.csv', 'value': 'df'},
],
placeholder='Choose CSV'
),
dmc.Button('Load data', id='load-button', n_clicks=0),
],
),
html.Div(
children=[
dag.AgGrid(
id='infinite-grid',
rowModelType="infinite",
columnDefs=generate_default_col_defs(),
columnSize="autoSize",
defaultColDef={'resizable': True, 'editable': False, 'sortable': True,
'minWidth': 150, 'maxWidth': 150, 'width': 150},
dashGridOptions={"rowBuffer": 0,
"maxBlocksInCache": 2,
"cacheBlockSize": 100,
"cacheOverflowSize": 2,
"maxConcurrentDatasourceRequests": 2,
"infiniteInitialRowCount": 1,
"pagination": True},
),
],
),
],
),
)
@callback(
output=[
Output('infinite-grid', "getRowsResponse"),
Output('infinite-grid', 'paginationGoTo'),
Output('infinite-grid', "columnDefs"),
],
inputs=[
Input('load-button', "n_clicks"),
Input('infinite-grid', "getRowsRequest"),
],
state=[
State('dropdown', "value"),
],
running=[
(Output('load-button', "disabled"), True, False),
],
# background=True,
prevent_initial_call=True
)
def update_layout(n_clicks, request, value):
if value:
# time.sleep(1)
dff = data.get(value).copy()
dff.insert(0, 'ID', dff.index)
if 'load-button' == ctx.triggered_id:
partial = dff.to_dict('records')[0:100]
response = {"rowData": partial, "rowCount": len(dff)}
return response, 0, generate_col_defs()
elif request:
partial = dff.to_dict('records')[request["startRow"]:request["endRow"]]
response = {"rowData": partial, "rowCount": len(dff)}
return response, no_update, generate_col_defs()
raise PreventUpdate
app.clientside_callback(
"""
(n, id) => {
if (n) {
grid = dash_ag_grid.getApi(id)
grid.showLoadingOverlay()
}
return window.dash_clientside.no_update
}
""",
Output('infinite-grid', "id"),
Input('load-button', "n_clicks"),
State('infinite-grid', 'id'),
prevent_initial_call=True
)
app.clientside_callback(
"""
(n, id) => {
grid = dash_ag_grid.getApi(id)
grid.hideOverlay()
return window.dash_clientside.no_update
}
""",
Output('infinite-grid', "id", allow_duplicate=True),
Input('infinite-grid', "getRowsResponse"),
State('infinite-grid', 'id'),
prevent_initial_call=True
)
if __name__ == '__main__':
app.run_server(debug=True)
The loading spinner only works when loading the new data, which technically when you first load the grid you have data showing. It also doesnt have any placeholders for the data and is cached, so there isnt a new grid call for the rowRequest.
Thanks much!!! Working good))))
if first grid loading:
loading for next page: