GithubHelp home page GithubHelp logo

plotly / dash-ag-grid Goto Github PK

View Code? Open in Web Editor NEW
165.0 165.0 24.0 6.95 MB

Dash AG Grid is a high-performance and highly customizable component that wraps AG Grid, designed for creating rich datagrids.

Home Page: https://dash.plotly.com/dash-ag-grid

License: MIT License

Python 67.63% JavaScript 32.37%

dash-ag-grid's Introduction

R-CMD-check CRAN Status CRAN Downloads monthly

An R package for creating interactive web graphics via the open source JavaScript graphing library plotly.js.

Installation

Install from CRAN:

install.packages("plotly")

Or install the latest development version (on GitHub) via {remotes}:

remotes::install_github("plotly/plotly")

Getting started

Web-based ggplot2 graphics

If you use ggplot2, ggplotly() converts your static plots to an interactive web-based version!

library(plotly)
g <- ggplot(faithful, aes(x = eruptions, y = waiting)) +
  stat_density_2d(aes(fill = ..level..), geom = "polygon") + 
  xlim(1, 6) + ylim(40, 100)
ggplotly(g)

https://i.imgur.com/G1rSArP.gifv

By default, ggplotly() tries to replicate the static ggplot2 version exactly (before any interaction occurs), but sometimes you need greater control over the interactive behavior. The ggplotly() function itself has some convenient “high-level” arguments, such as dynamicTicks, which tells plotly.js to dynamically recompute axes, when appropriate. The style() function also comes in handy for modifying the underlying trace attributes (e.g. hoveron) used to generate the plot:

gg <- ggplotly(g, dynamicTicks = "y")
style(gg, hoveron = "points", hoverinfo = "x+y+text", hoverlabel = list(bgcolor = "white"))

https://i.imgur.com/qRvLgea.gifv

Moreover, since ggplotly() returns a plotly object, you can apply essentially any function from the R package on that object. Some useful ones include layout() (for customizing the layout), add_traces() (and its higher-level add_*() siblings, for example add_polygons(), for adding new traces/data), subplot() (for combining multiple plotly objects), and plotly_json() (for inspecting the underlying JSON sent to plotly.js).

The ggplotly() function will also respect some “unofficial” ggplot2 aesthetics, namely text (for customizing the tooltip), frame (for creating animations), and ids (for ensuring sensible smooth transitions).

Using plotly without ggplot2

The plot_ly() function provides a more direct interface to plotly.js so you can leverage more specialized chart types (e.g., parallel coordinates or maps) or even some visualization that the ggplot2 API won’t ever support (e.g., surface, mesh, trisurf, etc).

plot_ly(z = ~volcano, type = "surface")

https://plot.ly/~brnvg/1134

Learn more

To learn more about special features that the plotly R package provides (e.g., client-side linking, shiny integration, editing and generating static images, custom events in JavaScript, and more), see https://plotly-r.com. You may already be familiar with existing plotly documentation (e.g., https://plotly.com/r/), which is essentially a language-agnostic how-to guide for learning plotly.js, whereas https://plotly-r.com is meant to be more wholistic tutorial written by and for the R user. The package itself ships with a number of demos (list them by running demo(package = "plotly")) and shiny/rmarkdown examples (list them by running plotly_example("shiny") or plotly_example("rmd")). Carson also keeps numerous slide decks with useful examples and concepts.

Contributing

Please read through our contributing guidelines. Included are directions for opening issues, asking questions, contributing changes to plotly, and our code of conduct.

dash-ag-grid's People

Contributors

alexcjohnson avatar aliwelchoo avatar annmariew avatar bsd3v avatar emilhe avatar farkites avatar gvwilson avatar liamconnors avatar ndrezn avatar sdidier-dev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dash-ag-grid's Issues

Dash AG Grid V2.0 Status

Dash AG Grid V2.0 Status

Security Issues

Add Features - Parity with DataTable

  • Be able to use dcc.Link in Markdown like in dcc.Markdown

  • Number Formatting (using d3-format like in DataTable)

  • Date handling and formatting

  • Adding and Deleting Rows (in progress)

  • Application assigned row ids

  • Components in Tooltips

  • Include selected_*, derived_virtual_*, derived_viewport_* props

  • Set and save filters (see example in docs)

  • Go to a page - see customizing pagination

Other Features - AG Grid Community

  • Handle rowClassRules and cellClassRules prop for conditional formatting
  • Add a columnState prop to show state of columns that are changed in the UI such as when pinning, sorting, changing width or order.
  • Buttons in cells
  • Date filter
  • Handle JavaScript functions (in progress)
  • Other components (cell renderers)
  • Components as props

Other Features - AG Grid Enterprise

If you or your company would like to sponsor features available in AG Grid Enterprise, please contact Plotly

Documentation App - hosted at https://dashaggrid.pythonanywhere.com/

  • Review/edit current content
  • Add more content from official AG Grid docs
  • Document security risks of html and JavaScript
  • Document props that don't trigger callback
  • Download to Excel example

Testing

  • Set up dash testing
  • Add tests

Issues

  • Fix errors and warnings showing in the console
  • Review issues or open PRs from previous Enterprise dash-ag-grid
  • update cellDataChanged when multiple cells updated
  • Reduce the number of props (In progress - AnnMarieW to make a list of props to keep)
  • Reduce bundle size and dependencies
    - Use external_stylesheets for themes rather than imported by the component?
    - possibly include a prop that can import d3 or not?

Filtering and Sorting with Client Side table interaction

When rowModelType="infinite", the table doesnt respond to sorting and filtering the same way, as denoted here:

https://www.ag-grid.com/react-data-grid/infinite-scrolling/#sorting--filtering

Here is an example of how to work with sorting and filtering inside the requests in an infinite model:

"""
Working with infinite scroll against a backend database in AG-Grid.
"""
import traceback

import dash_ag_grid as dag
from dash import Dash, Input, Output, html, no_update, State, ctx
import pandas as pd
import requests

app = Dash(__name__)

raw_data = requests.get(
    r"https://www.ag-grid.com/example-assets/olympic-winners.json"
).json()

df = pd.DataFrame(data=raw_data)
pd.to_datetime(df['date'], dayfirst=True)

columnDefs = [
    {"field": "athlete", "filter": False},
    {"field": "country", "filter": False},
    {
        "headerName": "Date",
        'field': 'date',
        "filter": "agDateColumnFilter",
        "valueGetter": {"function": "d3.timeParse('%d/%m/%Y')(params.data.date)"},
        "valueFormatter": {"function": "params.data.date"},
        "filterParams": {
            "browserDatePicker": True,
            "minValidYear": 2000,
            "maxValidYear": 2021,
        },
    },
]

app.layout = html.Div(
    [
        dag.AgGrid(
            id="grid1",
            rowModelType="infinite",
            rowSelection="multiple",
            columnSize="sizeToFit",
            columnDefs=columnDefs,
            defaultColDef={"sortable": True, 'filter': True},
            # 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=1,
            multiSortKey=True
        ),
    ]
)

operators = {
    'greaterThanOrEqual': 'ge',
     'lessThanOrEqual':'le',
     'lessThan': 'lt',
     'greaterThan': 'gt',
     'notEqual': 'ne',
     'equals': 'eq'
    }

def filterDf(df, data, col):
    ##To-Do fix date filtering
    if data['filterType'] == 'date':
        crit1 = data['dateFrom']
        if 'dateTo' in data:
            crit2 = data['dateTo']
    else:
        crit1 = data['filter']
        if 'filterTo' in data:
            crit2 = data['filterTo']
    if data['type'] == 'contains':
        df = df.loc[df[col].str.contains(crit1)]
    elif data['type'] == 'notContains':
        df = df.loc[~df[col].str.contains(crit1)]
    elif data['type'] == 'startsWith':
        df = df.loc[df[col].str.startswith(crit1)]
    elif data['type'] == 'notStartsWith':
        df = df.loc[~df[col].str.startswith(crit1)]
    elif data['type'] == 'endsWith':
        df = df.loc[df[col].str.endswith(crit1)]
    elif data['type'] == 'notEndsWith':
        df = df.loc[~df[col].str.endswith(crit1)]
    elif data['type'] == 'inRange':
        if data['filterType'] == 'date':
            df = df.loc[df[col].astype('datetime64[ns]').between_time(crit1, crit2)]
        else:
            df = df.loc[df[col].between(crit1, crit2)]
    elif data['type'] == 'blank':
        df = df.loc[df[col].isnull()]
    elif data['type'] == 'notBlank':
        df = df.loc[~df[col].isnull()]
    else:
        df = df.loc[getattr(df[col], operators[data['type']])(crit1)]
    return df

@app.callback(
    Output("grid1", "getRowsResponse"),
    Input("grid1", "getRowsRequest")
)
def infinite_scroll(request):
    dff = df.copy()
    orig_dff = dff.copy()

    if request['filterModel']:
        fils = request['filterModel']
        for k in fils:
            try:
                if 'operator' in fils[k]:
                    if fils[k]['operator'] == 'AND':
                        dff = filterDf(dff, fils[k]['condition1'], k)
                        dff = filterDf(dff, fils[k]['condition2'], k)
                    else:
                        dff1 = filterDf(dff, fils[k]['condition1'], k)
                        dff2 = filterDf(dff, fils[k]['condition2'], k)
                        dff = pd.concat([dff1, dff2])
                else:
                    dff = filterDf(dff, fils[k], k)
            except:
                print(traceback.format_exc())
                pass
        dff = dff

    if request['sortModel']:
        sorting = []
        asc = []
        for sort in request['sortModel']:
            sorting.append(sort['colId'])
            if sort['sort'] == 'asc':
                asc.append(True)
            else:
                asc.append(False)
        dff = dff.sort_values(by=sorting, ascending=asc)

    partial = dff.iloc[request["startRow"]: request["endRow"]]
    return {"rowData": partial.to_dict("records"), "rowCount": len(orig_dff.index)}


if __name__ == "__main__":
    app.run_server(debug=True, port=12345)

Allow conditionals in valueFormatter parameter

The valueFormatter parameter for column definition is excellent but could be better if it allowed conditionals. For instance, I am setting a percentage format for the value in the below code. Therefore, I want to add a conditional that applies that format as long as value*100 is not NaN. If NaN, then use another function.

"valueFormatter": "Number(value*100).toFixed(0) + '%'",

Custom aggFunc with Row Grouping

For use with a future push.

Here is an example app.py:

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

app = dash.Dash(__name__)

    data = requests.get(
        r"https://www.ag-grid.com/example-assets/olympic-winners.json"
    ).json()

    columnDefs = [
        # Row group by country and by year is enabled.
        {
            'field': 'country',
            'rowGroup': True,
            'hide': True,
            'suppressColumnsToolPanel': True,
        },
        {
            'field': 'sport',
            'rowGroup': True,
            'hide': True,
            'suppressColumnsToolPanel': True,
        },
        {
            'field': 'year',
            'pivot': True,
            'hide': True,
            'suppressColumnsToolPanel': True,
        },
        {"field": "gold", "sortable": True, "filter": True, 'aggFunc': 'sum'},
        {"field": "silver", "sortable": True, "filter": True, 'aggFunc': 'sum'},
        {"headerName": "ratio", 'colId': 'goldSilverRatio',
         'aggFunc': {'function': 'ratioAggFunc(params)'},
         'valueGetter': {'function': 'ratioValueGetter(params)'},
         'valueFormatter': {'function': 'ratioFormatter(params)'},
         }
    ]

    app.layout = html.Div(
        [
            dcc.Markdown("Demonstration of row groupings in a Dash AG Grid."),
            dcc.Markdown("This grid groups first by country and then by year."),
            dag.AgGrid(
                columnDefs=columnDefs,
                rowData=data,
                rowSelection="multiple",
                defaultColDef=dict(
                    resizable=True,
                ),
                id="grid",
                suppressAggFuncInHeader=True,
                enableEnterpriseModules=True,
            ),
        ]
    )

app.run()

And then the functions:

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

dagfuncs.ratioValueGetter = function (params) {
  if (!(params.node && params.node.group)) {
    // no need to handle group levels - calculated in the 'ratioAggFunc'
    return createValueObject(params.data.gold, params.data.silver);
  }
}
dagfuncs.ratioAggFunc = function (params) {
  let goldSum = 0;
  let silverSum = 0;
  params.values.forEach((value) => {
    if (value && value.gold) {
      goldSum += value.gold;
    }
    if (value && value.silver) {
      silverSum += value.silver;
    }
  });
  return createValueObject(goldSum, silverSum);
}

function createValueObject(gold, silver) {
  return {
    gold: gold,
    silver: silver,
    toString: () => `${gold && silver ? gold / silver : 0}`,
  };
}

dagfuncs.ratioFormatter = function (params) {
  if (!params.value || params.value === 0) return '';
  return '' + Math.round(params.value * 100) / 100;
}

Scrolling locks grid

With a single ag_grid in the layout (no callbacks) and about 300 records, scrolling the grid up and down with the mouse wheel for maybe 15 seconds causes the browser to become intermittent and finally die. (repeatable in Chrome and Firefox).

  • Alpha version 2.0.0a2
  • Dataframe is [318 rows x 15 columns]

Odd observation: It happens much faster if there is an external style_sheet (external_stylesheets=[dbc.themes.DARKLY]). With no stylesheet it still occurs, but take longer.

tbl = 'Site'

app = Dash(__name__, external_stylesheets=[dbc.themes.DARKLY])

table = dag.AgGrid(
            id='ag_grid',

            columnDefs=columnDefs,
            className='ag-theme-alpine-dark',
            rowData=df.to_dict('records'),
            columnSize='autoSizeAll',     # sizeToFit, autoSizeAll
            # cellStyle=cellStyle,      # would be used for conditional formatting (see demo-stock-portfolio.py)
            dashGridOptions={
                'undoRedoCellEditing': True,
                'rowSelection': 'single'
            },
            defaultColDef=dict(
                resizable=True,
                sortable=True,
                filter=True,
                floatingFilter=True
                ),
            )

header = html.Div(tbl + ' Data',
                  className='h2 p-2 text-white bg-primary text-center')

app.layout = dbc.Container(
    [
        header,
        dbc.Row(dbc.Col(table), className='py-4'),   
    ],
)

a typical columnDef:

 {
                'headerName': 'Smithsonian',
                'field': 'Smithsonian',
                'filter': 'agTextColumnFilter',
                'editable': False,
}

error message: `dangerously_allow_code`

Thanks for your work.

I followed the steps to test this tool, and encountered this error:

TypeError: The dash_ag_grid.AgGridcomponent (version 2.0.0a1) with the ID "portfolio-grid" received an unexpected keyword argument:dangerously_allow_code``

Thanks for any potential help provided!

ValueFormatter with advanced grouping

Hello, thanks for your works.

I've been working with a table with multiple layers of columns,
like years, quarters, months, and so on.

I was exporting formatted numbers as string,
but I saw that valueFormatter is available from a2, I wanted try it.
but it seems like I won't able to get the valueFormatter working from 2nd level.

Would there be a way for me to get the params.value within those groups?

I just made a quick example from this.

Example
import dash_ag_grid as dag
from dash import Dash, html, dcc
import plotly.express as px

df = px.data.gapminder()

app = Dash(__name__)

columnDefs = [
    {"headerName": "Country", "field": "country", "flex":1},
    {"headerName": "Continent", "field": "continent", "flex":1},
    {"headerName": "Year", "field": "year", "flex":1},
    {"headerName": "grouped",
     "flex":1,
     "groupId":"group1",
     "children":
        [
            {
                "headerName": "Population",
                "field": "pop",
                "flex":1,
                "valueFormatter": {"function": "d3.format(',.0f')(params.value)"},
            },
            {
                "headerName": "GDP per Capita",
                "field": "gdpPercap",
                "flex":1,
                "valueFormatter": {"function": "d3.format('$,.1f')(params.value)"},
            },
            {
                "headerName": "group2",
                "groupId":"group2",
                "flex":1,
                "children":[
                    {
                        "headerName": "Life_Expectancy",
                        "field": "lifeExp",
                        "flex":1,
                        "valueFormatter": {"function": "d3.format(',.0f')(params.value)"},
                    },
                    {
                        "headerName": "GDP per Capita2",
                        "field": "gdpPercap",
                        "flex":1,
                        "valueFormatter": {"function": "d3.format('$,.1f')(params.value)"},
                    },
                ]
            },
        ]
    }
]

app.layout = html.Div(
    [
        dcc.Markdown("Gapminder Data with formatting"),
        dag.AgGrid(
            columnDefs=columnDefs,
            defaultColDef="",
            rowData=df.to_dict("records"),
            columnSize="sizeToFit",
        ),
    ],
    style={"margin": 20},
)

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

I hope I am just missing something,
Thanks for the works once again!

Feature Request -- return filter query

Hello!

Thank you so much for making this package public, it is AMAZING!!

I did have one request I was hoping could be added.

I'm doing a lot of work with filtering tables and storing the results alongside the query, and I see that you can pull out the resulting data using virtualRowData but I was wondering if there is any way to access the filter query on that table from a callback.

For example, if I start with a table of 100 rows and filtering on 'column A > 2' results in 50 rows, I can access those 50 rows of data but I can't see a way to retrieve 'column A > 2'. With more complex filters on multiple columns this would be extremely helpful.

Thank you!

valueFormatter does not work on initial load when in callback

I am working with a variety of dataframes where I'm trying to set the valueFormatters for various columns. Given the nature of the app I'm making, both the data and the columnDefs for the table are returned to the grid object in a callback that takes multiple inputs. It appears that the valueFormatters do not register on initial loading of the table but will register once the data is reloaded when an input is changed.

Here is a video showing the behavior I'm (attempting) to describe. It is a simplified version of a larger app that I am working on.

Let me know if you need more information.

agGrid_behavior.mov

Does comparator work when defining table columns?

I'm trying to write a custom sort function for a table column. Here's what I have:

    def make_author_table(self):
        def author_sort(valueA, valueB, nodeA=None, nodeB=None,
                        isDescending=True):
            sortA = self.authors.loc[self.authors.fullname == valueA,
                                     'sortname'].values[0]
            sortB = self.authors.loc[self.authors.fullname == valueB,
                                     'sortname'].values[0]
            if sortA > sortB:
                return 1
            elif sortA < sortB:
                return -1
            else:
                return 0
    
        authors = self.authors[['fullname', 'gender', 'nationality',
                                'demographic']].copy()
        authors.columns = ['Name', 'Gender', 'Nationality', 'Demographic']
        columnDefs = [{'field': 'Name', 'editable': True,
                       'comparator': author_sort},
                      {'field': 'Gender', 'editable': True},
                      {'field': 'Nationality', 'editable': True},
                      {'field': 'Demographic', 'editable': True}]
        author_table = dag.AgGrid(
            id='authors',
            className='ag-theme-alpine',
            columnDefs=columnDefs,
            rowData=authors.to_dict("records"),
            columnSize="sizeToFit",
            defaultColDef={"resizable":True, "sortable":True, "filter":True},
            dashGridOptions={"undoRedoCellEditing":True, "rowSelection":"single"})
        return author_table

This is the error I get:

Traceback (most recent call last):
  File "/Users/mburger/anaconda3/lib/python3.9/site-packages/dash/_callback.py", line 480, in add_context
    jsonResponse = to_json(response)
  File "/Users/mburger/anaconda3/lib/python3.9/site-packages/dash/_utils.py", line 22, in to_json
    return to_json_plotly(value)
  File "/Users/mburger/anaconda3/lib/python3.9/site-packages/plotly/io/_json.py", line 123, in to_json_plotly
    return json.dumps(plotly_object, cls=PlotlyJSONEncoder, **opts)
  File "/Users/mburger/anaconda3/lib/python3.9/json/__init__.py", line 234, in dumps
    return cls(
  File "/Users/mburger/anaconda3/lib/python3.9/site-packages/_plotly_utils/utils.py", line 59, in encode
    encoded_o = super(PlotlyJSONEncoder, self).encode(o)
  File "/Users/mburger/anaconda3/lib/python3.9/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/Users/mburger/anaconda3/lib/python3.9/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/Users/mburger/anaconda3/lib/python3.9/site-packages/_plotly_utils/utils.py", line 136, in default
    return _json.JSONEncoder.default(self, obj)
  File "/Users/mburger/anaconda3/lib/python3.9/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type function is not JSON serializable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/mburger/anaconda3/lib/python3.9/site-packages/flask/app.py", line 1820, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/mburger/anaconda3/lib/python3.9/site-packages/flask/app.py", line 1796, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/Users/mburger/anaconda3/lib/python3.9/site-packages/dash/dash.py", line 1273, in dispatch
    ctx.run(
  File "/Users/mburger/anaconda3/lib/python3.9/site-packages/dash/_callback.py", line 482, in add_context
    _validate.fail_callback_output(output_value, output)
  File "/Users/mburger/anaconda3/lib/python3.9/site-packages/dash/_validate.py", line 326, in fail_callback_output
    _validate_value(val, index=i)
  File "/Users/mburger/anaconda3/lib/python3.9/site-packages/dash/_validate.py", line 302, in _validate_value
    _raise_invalid(bad_val=j, outer_val=val, path=p, index=index)
  File "/Users/mburger/anaconda3/lib/python3.9/site-packages/dash/_validate.py", line 230, in _raise_invalid
    raise exceptions.InvalidCallbackReturnValue(
dash.exceptions.InvalidCallbackReturnValue: The callback for `<Output `tab_content.children`>`
                returned a tree with one value having type `AgGrid`
                which is not JSON serializable.


The value in question is located at
[0] Div 
[0] AgGrid (id=authors),

   <snip>

                In general, Dash properties can only be
                dash components, strings, dictionaries, numbers, None,
                or lists of those.

I can't find a python example for "comparator", so I'm not sure if I've done this wrong, if it's a bug, or just a feature that hasn't been implemented.

Accessing event attributes of AG Grid

Problem statement: event callbacks are not being fired

Explanation: I tried to get modelUpdated and viewportChanged callbacks when filter is applied on AG-grid but could not succeeded yet.

Version:
dash-ag-grid==2.0.0a1

Code snippet:

@app.callback(  Output("chart", "figure"),
                Input("details-table", "modelUpdated"),
                Input("details-table", "viewportChanged"))
def model_updated(data, vp):
    print(data, vp)
    return go.Figure()

Community Forum:
https://community.plotly.com/t/how-to-capture-viewportchanged-or-modelupdated-events-in-the-ag-grid/72139

Glitchy Column State between Dash Layout repeat

I believe that this issue specifically applies to a very unique use case, based upon how dash operates:

import dash_ag_grid as dag
from dash import Dash, html, dcc, Input, Output, State
import dash_bootstrap_components as dbc
import pandas as pd
import yfinance as yf
import dash

app = Dash(__name__, external_stylesheets=[dbc.themes.DARKLY],
           meta_tags=[{'http-equiv': 'content-security-policy',
                       'content': "default-src 'self'; script-src 'self' 'unsafe-inline';"
                                  " style-src https://* 'self' 'unsafe-inline'; "
                                  "font-src data: https://* 'self' 'unsafe-inline';"
                                  "img-src data: https://* 'self'"}],
            use_pages=True, pages_folder=''
           )

equities = {
    "AAPL": "Apple",
    "MSFT": "Microsoft",
    "AMZN": "Amazon",
    "GOOGL": "Alphabet",
    "TSLA": "Tesla",
    "BRK-B": "Berkshire Hathaway",
    "UNH": "United Health Group",
    "JNJ": "Johnson & Johnson",
}


def get_stock_data():
    return yf.download(tickers=list(equities.keys()), period="2y", group_by="ticker")


stock_data = get_stock_data()


def last_close(ticker):
    return stock_data[ticker]["Close"].iloc[-1]


data = {
    "ticker": [ticker for ticker in equities],
    "company": [name for name in equities.values()],
    "quantity": [75, 40, 100, 50, 40, 60, 20, 40],
    "price": [last_close(ticker) for ticker in equities],
}
df = pd.DataFrame(data)

columnDefs = [
    {
        "headerName": "Stock Ticker",
        "field": "ticker",
        "type": "textAligned",
        "filter": True
    },
    {
        "headerName": "Company",
        "field": "company",
        "type": "textAligned",
        "filter": True
    },
    {
        "headerName": "Shares",
        "field": "quantity",
        "editable": True,
    },
    {
        "headerName": "Last Close Price",
        "field": "price",
        "cellRenderer": "agAnimateShowChangeCellRenderer",
    },
]


defaultColDef = {
    "type": ["rightAligned"],
    "filter": "agNumberColumnFilter",
    "resizable": True,
    "sortable": True,
    "editable": False,
    "floatingFilter": True,
}

table = dag.AgGrid(
    id="portfolio-grid",
    className="ag-theme-alpine-dark",
    columnDefs=columnDefs,
    rowData=df.to_dict("records"),
    columnSize=None,
    defaultColDef=defaultColDef,
    rowSelection="single",
    dashGridOptions={'undoRedoCellEditing':True, 'undoRedoCellEditingLimit': 20},
    getRowStyle={
                "styleConditions": [
                    {"condition": "data.quantity > 50", "style": {"color": "orange"}},
                ]
            },
)

header = html.Div("My Portfolio", className="h2 p-2 text-white bg-primary text-center")

dash.register_page('Home', path='/', layout=table)
dash.register_page('1', layout=table)
dash.register_page('2', layout=table)
dash.register_page('3', layout=table)

app.layout = dbc.Container(
    [
        header,
        dbc.Nav([dbc.NavLink(pg['name'], href=pg['path']) for pg in dash.page_registry.values()]),
        dbc.Row(dbc.Col(dash.page_container, className="py-4")),
    ],
)

if __name__ == "__main__":
    app.run_server(debug=True, port=12345)

As you navigate through the pages using the nav links that are internal, the table's state semi refreshes. Some of the pinning stays, while the column order resets. After the first pin, it doesnt take the second pin immediately when switching between pages. This case would be really on display when a page layout has different variables in the path. (/stocks/<ticker>)

Storing column layouts for utilization between the same layout may be a useful feature, we should look into fleshing this out more to save and load fully when it is the desired outcome. Otherwise, when disabled, this state should be wiped out.

sizeToFit won't work if you set width (initial load)

requirements.txt:
dash-ag-grid==2.0.0a3
dash==2.8.1

Code to reproduce the error:

import dash_ag_grid as dag
import dash
from dash import html

app = dash.Dash(__name__)

columnDefs = [
    {"headerName": "Make", "field": "make", "width": 90},
    {"headerName": "Price", "field": "price", "width": 30},
]

rowData = [
    {"make": "Toyota", "model": "Celica", "price": 35000},
    {"make": "Porsche", "model": "Boxter", "price": 72000},
]

app.layout = html.Div(
    [
        dag.AgGrid(
            id="input",
            columnSize="sizeToFit",
            columnDefs=columnDefs,
            rowData=rowData,
        ),
    ]
)


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

Output

image

autoSizeAllColumns bug

Error when updating autoSizeAllColumns prop in a callback:

image

Here is MRE

from dash import Dash, html, Input, Output
import dash_ag_grid as dag
import pandas as pd

df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv")

app = Dash(__name__)

grid = dag.AgGrid(
    id="size-grid",
    rowData=df.to_dict("records"),
    columnDefs=[{"field": i, "id": i} for i in df.columns],
    defaultColDef={"resizable": True},
    columnSize="sizeToFit",
)


app.layout = html.Div([
    html.Button("Auto Size", id="auto-size"),
    grid
])


@app.callback(
    Output("size-grid", "autoSizeAllColumns"),
    Input("auto-size", "n_clicks"),
   # prevent_initial_call=True
)
def change_size(_):
    return True


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

Grid unresponsive with large datasets when columns are set to autoSizeAll

Here is a demo app to reproduce:


import dash_ag_grid as dag
import dash
from dash import Input, Output, html, dcc
import pandas as pd

app = dash.Dash(__name__)


df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/liquor_iowa_2021.csv"
)


app.layout = html.Div(
    [
        dcc.Markdown(
            "Switch between autosize and size to fit to see the columns respond. Columns can also be resized by dragging at their edge."
        ),
        dcc.RadioItems(
            id="columnSizing",
            options=[
                {"label": i, "value": j}
                for i, j in [
                    ("Auto size", "autoSizeAll"),
                    ("Size to fit", "sizeToFit"),
                ]
            ],
            value="autoSizeAll",
        ),
        dag.AgGrid(
            id="input",
            columnDefs=[{"field": i} for i in df.columns],
            rowData=df.to_dict("records"),
            columnSize="autoSizeAll",
            defaultColDef=dict(
                resizable=True,
                sortable=True,
                filter=True,
                minWidth=100
            ),
        ),
    ]
)


@app.callback(Output("input", "columnSize"), Input("columnSizing", "value"))
def column_sizing(size_type):
    return size_type


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




AgGrid cellClicked not working twice in a row

The event cellClicked will not be activated twice for the same cell in a row.

Here is and example:

import pandas as pd
from dash import html,Input, Output, Dash
import dash_bootstrap_components as dbc
import dash_ag_grid

#
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

# sample dataframe
df = pd.DataFrame({"col1": [1, 2, 3], "col2": ["A", "B", "C"]})

# column definition
column_defs = [
    {
        "headerName": "col1",
        "field": "col1",
    },
    {
        "headerName": "col2",
        "field": "col2",
    },
]
# layout
app.layout = html.Div(
    [
        dash_ag_grid.AgGrid(
            id="my-grid",
            rowData=df.to_dict("records"),
            columnDefs=column_defs,
        ),
    ]
)



@app.callback(
    Output("my-grid", "rowData"),
    Input("my-grid", "cellClicked")
)
def remove_line(cell_clicked):
    if cell_clicked is not None:
        col_id = cell_clicked["colId"]
        row_index = cell_clicked["rowIndex"]
        print(f"You clicked the icon in row {row_index} and col {col_id}")
    return df.to_dict("records")

if __name__ == '__main__':
    app.run_server(debug=True)

When you clicked twice on the same cel you get only one activation of the callback function:

You clicked the icon in row 0 and col col2

Instead you should have:

You clicked the icon in row 0 and col col2
You clicked the icon in row 0 and col col2

The only way to have two activation on the same cell is if you click on another and then go back:

You clicked the icon in row 1 and col col2
You clicked the icon in row 2 and col col2
You clicked the icon in row 1 and col col2

download pdf file issue with hyper link in table

I am facing an issue with downloading a local pdf file with hyperlink in table. My code is as follows:

# step-01
df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/solar.csv")
if 'index' not in df:
    df['index'] = list(df.index)
df['filepath'] = df['index'].apply(lambda s : os.path.join("assets\data\gtre_reports", f"{s}.pdf"))
df['link'] = df[['State', 'filepath']].apply(lambda s : f"[{s[0]}]({s[1]})", axis = 1)

app = Dash(__name__)

# step-02
def get_agrid(df):
    
    # select columns as per datatype
    link_columns = [s for s in df if s in ['link']]
    object_columns = [s for s in df.select_dtypes(include = "object") if s not in link_columns]
    numeric_columns = [s for s in df.select_dtypes(include = np.number) if (s not in link_columns) and (s not in object_columns)]

    # create column definitions
    columnDefs = [{"headerName": "Row ID", "valueGetter": {"function": "params.node.id"}, 'rowDrag': True}] + \
        [{"field" : i, "id" : i,"cellRenderer": "markdown", "resizable": True} for i in link_columns] + \
        [{"field" : i, "id" : i, "editable": True, "resizable": True} for i in object_columns] + \
        [{"field" : i, "id" : i, "type": "rightAligned", "editable": True, "resizable": True} for i in numeric_columns]

    # create default column definitions
    defaultColDef = {"resizable": True, "sortable": True, "filter": True, "editable": True}
    


    # create grid
    grid = dag.AgGrid(
        id="grid-01",
        rowData=df.to_dict("records"),
        columnDefs=columnDefs,
        defaultColDef=defaultColDef,
        columnSize="autoSizeAll",
        dashGridOptions={"rowDragManaged": True,
                         "columnHoverHighlight": True,
                         "rowMultiSelectWithClick": True,
                         "enableCellTextSelection": True,
                         "ensureDomOrder": True,
                         "undoRedoCellEditing": True,
                         "undoRedoCellEditingLimit": 20,
                         "editType": "fullRow",
                         "pagination": True,
                         "paginationPageSize": 5,
                         },
        className="ag-theme-alpine", # ag-theme-balham, ag-theme-alpine-dark, ag-theme-material , ag-bootstrap
        csvExportParams={
            "fileName": "download.csv",
        },
    )
    
    return grid

grid = get_agrid(df)

# step-03
app.layout = html.Div(
    [
        grid,
    ],
 )

# step-04
if __name__ == "__main__":
    app.run_server(debug=True)

Its output is as follows:
image

the dataframe is like:
image

The main issue is that when I click hyper link, it does not download the pdf file which is link to a cell. it only refresh the page and does not download the pdf file.

I am using:
python 3.10.9
dash 2.9.2
dash-ag-grid 2.0.0a5

Grid freezes after interacting with agSetColumnFilter and trying to switch pages

Using a multi-page Dash app, after interacting with an agSetColumnFilter (deselecting, selecting options) I try to switch pages but the page freezes and CPU usage goes to ~100%. I have also noticed this with agMultiColumnFilter. Downgrading AG Grid packages to v28 seems to alleviate this specific issue. This is possible due to some filter changes in v29. Simple example:

from dash import Dash, html, dcc, callback
import dash
import dash_ag_grid as dag # dash-ag-grid==2.0.0a5
import pandas as pd

app = Dash(__name__, use_pages=True , pages_folder="")

# Import data
df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv")
df_solar = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/solar.csv")

# Home
home_layout = dag.AgGrid(
    id='home-grid',
    enableEnterpriseModules=True,
    rowData=df.to_dict('records'),
    columnDefs=[
        {
            'field': 'athlete',
            'filter': 'agSetColumnFilter',
            'floatingFilter': True
        },
        {
            'field': 'age',
        }
    ]
)
other_layout = dag.AgGrid(
    id='other-grid',
    enableEnterpriseModules=True,
    rowData=df_solar.to_dict('records'),
    columnDefs=[
        {
            'field': 'State',
            'filter': 'agSetColumnFilter',
            'floatingFilter': True
        },
        {
            'field': 'Number of Solar Plants',
        }
    ]
)

# Register pages
dash.register_page("home",  path='/', layout=home_layout)
dash.register_page("other", layout=other_layout)

# App layout
app.layout = html.Div([
    html.Div(
        [
            html.Div(
                dcc.Link(
                    f"{page['name']} - {page['path']}", href=page["relative_path"]
                )
            )
            for page in dash.page_registry.values()
        ]
    ),
    dash.page_container,
])


if __name__ == '__main__':
    app.run_server(debug=True, port=8060)

Writing Secure Dash apps with AG Grid

Writing secure Dash apps with AG Grid

See more information at: https://www.ag-grid.com/react-data-grid/security/

Here is a list of the security issue that need to be addressed before V2.0 is released:

Rendering raw HTML

Certain components can render raw HTML, which can lead to XSS attacks. By default, this is disabled.
Enable with dangerously_allow_code=True on both the column level and the component level.

  • Markdown Component
  • headerComponentParams.template
  • overlayNoRowsTemplate.
  • overlayLoadingTemplate

JavaScript code

By default you cannot use functions in dash props. However AG Grid allows expressions which are strings that get converted to functions and then executed as an option for many grid properties. Enable with dangerously_allow_code=True

  • cellClassRules
  • rowClassRules
  • valueGetters
  • valueSetter
  • valueFormatter
  • valueParser
  • filterValueGetter

Status (in progress)

Function parser

  • Rather than allowing string expressions, create a function parser that will allow or disable certain functionality.

Cell expressions

Whenever the grid comes across a value starting with '=', it will treat it as an expression.
Enable cell expressions, set enableCellExpressions=True in dashGridOptions.
Should this be disabled?

  • completed

Custom functions

Allow for custom javascript functions from the assets folder
Bundle with dash-ag-grid:

  • d3-format for number formatting consistent with DataTable
  • others?
    Status - in progress

Content Security Policy (CSP)

String expression can be disabled in the CSP. For example:

meta_tags = [
    {
        "http-equiv": "content-security-policy",
        "content": "default-src 'self'; script-src 'self' 'unsafe-inline';"
        " style-src https://* 'self' 'unsafe-inline'; "
        "font-src data: https://* 'self' 'unsafe-inline';"
        "img-src data: https://* 'self'",
    }
]
  • Make a variable for the above CSP so that it can be included like this:
    app = Dash(__name__, meta_tags = [dag.security.CSP])

props review

Props set by setProp

  • autoSizeAllColumns - change to true or 'skip headers' - resets itself to false after applying, later we may add other values for more control
  • autoSizeAllColumnsSkipHeaders - drop
  • cellClicked
  • cellValueChanged
  • clickData - change to cellRendererData
  • columnDefs
  • columnState
  • dashGridOptions - don't do setProps anymore, but keep the prop!
  • virtualRowData
  • defaultColDef
  • deleteSelectedRows
  • deselectAll
  • exportDataAsCsv
  • getDetailRequest
  • getDetailResponse
  • getRowsRequest
  • getRowsResponse - add setProps
  • gridReady - remove
  • hoverData - remove
  • resetColumnState
  • rowData
  • rowTransaction
  • selectAll - change to true or 'filtered' - resets itself to false after applying, later we may add other values for more control
  • selectAllFiltered - remove
  • selectedRows
  • updateColumnState - Alex to investigate removing, but ensure large data sets still work

Default Props

style: {height: '400px', width: '100%'},
className: 'ag-theme-alpine',
resetColumnState: false,
exportDataAsCsv: false,
selectAll: false,
selectAllFiltered: false,
deselectAll: false,
autoSizeAllColumns: false,
autoSizeAllColumnsSkipHeaders: false,
enableEnterpriseModules: false,
updateColumnState: false,
persisted_props: ['selectedRows'],
persistence_type: 'local',
suppressDragLeaveHidesColumns: true,
dangerously_allow_code: false,
rowModelType: 'clientSide',

PropTypes

  • cellStyle - move into defaultColDef and columnDefs, take out of top level
  • theme - remove
    /********************************
     * DASH PROPS
     *******************************/
    id: PropTypes.string,
    
    setProps: PropTypes.func,
    
    style: PropTypes.object,
    
    className: PropTypes.string,
    
    persistence: PropTypes.oneOfType([
        PropTypes.bool,
        PropTypes.string,
        PropTypes.number,
    ]),
    
    persisted_props: PropTypes.arrayOf(PropTypes.string),

    persistence_type: PropTypes.oneOf(['local', 'session', 'memory']),

    dangerously_allow_code: PropTypes.bool,

    /********************************
     * CUSTOM PROPS
     *******************************/

    resetColumnState: PropTypes.bool,
    
    exportDataAsCsv: PropTypes.bool,

    selectAll: PropTypes.bool,

    selectAllFiltered: PropTypes.bool,

    deselectAll: PropTypes.bool,

    autoSizeAllColumns: PropTypes.bool,

    autoSizeAllColumnsSkipHeaders: PropTypes.bool,
    
    updateColumnState: PropTypes.bool,

    deleteSelectedRows: PropTypes.bool,

    rowTransaction: PropTypes.shape({
        async: PropTypes.bool,
        add: PropTypes.array,
        update: PropTypes.array,
        remove: PropTypes.array,
        addIndex: PropTypes.number,
    }),

    getRowId: PropTypes.string,


    columnState: PropTypes.array,

    csvExportParams: PropTypes.shape({
        columnSeparator: PropTypes.string,
        suppressQuotes: PropTypes.bool,
        prependContent: PropTypes.string,
        appendContent: PropTypes.string,
        allColumns: PropTypes.bool,
        columnKeys: PropTypes.arrayOf(PropTypes.string),
        fileName: PropTypes.string,
        onlySelected: PropTypes.bool,
        onlySelectedAllPages: PropTypes.bool,
        skipColumnGroupHeaders: PropTypes.bool,
        skipColumnHeaders: PropTypes.bool,
        skipRowGroups: PropTypes.bool,
        skipPinnedTop: PropTypes.bool,
        skipPinnedBottom: PropTypes.bool,
    }),

    columnSize: PropTypes.oneOf(['sizeToFit', 'autoSizeAll', null]),

    theme: PropTypes.oneOf(['alpine', 'balham', 'material', 'bootstrap']),

    cellStyle: PropTypes.shape({ 
        styleConditions: PropTypes.arrayOf(
            PropTypes.shape({
                condition: PropTypes.string.isRequired,
                style: PropTypes.object.isRequired,
            })
        ),
        defaultStyle: PropTypes.object,
    }),

    getRowStyle: PropTypes.shape({
        styleConditions: PropTypes.arrayOf(
            PropTypes.shape({
                condition: PropTypes.string.isRequired,
                style: PropTypes.object.isRequired,
            })
        ),
        defaultStyle: PropTypes.object,
    }),

    getRowsRequest: PropTypes.shape({
        startRow: PropTypes.number,
        endRow: PropTypes.number,
        sortModel: PropTypes.any,
        filterModel: PropTypes.any,
        context: PropTypes.any,
        successCallback: PropTypes.func,
        failCallback: PropTypes.func,
    }),

    getDetailRequest: PropTypes.shape({
        data: PropTypes.any,
        requestTime: PropTypes.any,
    }),

    getDetailResponse: PropTypes.any,

    clickData: PropTypes.any,

    hoverData: PropTypes.any,

    getRowsResponse: PropTypes.shape({
        rowData: PropTypes.arrayOf(PropTypes.object),
        rowCount: PropTypes.number,
        storeInfo: PropTypes.any,
    }),

    licenseKey: PropTypes.string,

    enableEnterpriseModules: PropTypes.bool,

    virtualRowData: PropTypes.any,

other props to remove:

  • rowValueChanged (may re-add later, or repurpose cellValueChanged for the editType='fullrow' case

Setting a start page doesn't work.

This might be an AG Grid bug: ag-grid/ag-grid#4233
Could also be related to when the initial page is set:

Here we set the initial page to page 5, but it starts at page 1

import dash_ag_grid as dag
from dash import Dash, html
import pandas as pd

app = Dash(__name__)


df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)


columnDefs = [
    {"field": "country"},
    {"field": "year"},
    {"field": "athlete"},
    {"field": "age"},
    {"field": "date"},
    {"field": "sport"},
    {"field": "total"},
]

app.layout = html.Div(
    dag.AgGrid(       
        columnDefs=columnDefs,
        rowData=df.to_dict("records"),
        dashGridOptions={ "pagination": True},
        paginationGoTo=5
    ),   
)

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

Bug: built-in JavaScript error on expand/collapse of row groups in v2.0.0rc1

JavaScript error is thrown when expanding/collapsing row groups in v2.0.0rc1.
This error does not appear in the previous v2.0.0a5 release.

To reproduce, run the following code and expand all groups and then try to collapse them sequentially.

from dash import Dash
import dash_ag_grid as dag

data = [{'G1':'A', 'G2':'B', 'Data':1000}]
columnDefs=[ {'field'  : col,
              'rowGroup': col in ['G1', 'G2'],
              } for col in data[0] ]
table_categories = dag.AgGrid(
    columnDefs=columnDefs,
    rowData=data, 
    enableEnterpriseModules=True,
)

app = Dash(__name__)
app.layout = table_categories

if __name__ == '__main__':
    app.run_server(debug=True)

Docs update:

I saw options to wrap and auto-set the header height in the docs but not the cell (maybe I did not see it). If it is not there, it would be helpful to put in the docs the options in the column definitions to wrapText and autoHeight to wrap contents in the cells.

image

https://blog.ag-grid.com/wrapping-column-header-text/

top row disappearing when sorting

I am currently experimenting moving some of my tables from simple dash-bootstrap-component to dash-ag-grid (to gain features where it makes sense). I have been toying with with 2.0.0rc1 and now 2.0.0rc2 and when I click on a column header to sort the table by that column, the top row usually disappear. It usually reappear when clicking again to sort the other direction, but then on some tables, it disappear as well when clicking a third time to remove the sorting. It consistently disappear on the first sorting click.
The tables are build on this model

dag.AgGrid(
        id="outstanding_gd",
        rowData=outstanding_df.to_dict("records"),
        columnDefs=[{"field": i} for i in outstanding_df.columns],
        defaultColDef={"resizable": True, "sortable": True, "filter": True},
        columnSize="sizeToFit",
        getRowId="params.data.State",
        dashGridOptions={"domLayout": "autoHeight"},
    )

The number of row is small so autoHeight does not cause issues. In fact, I regularly have less than 4 rows in those tables which means that even with autoHeight, I have some blank space below the table.

Importing React components in dashAgGridComponentFunctions

Hi,

I am trying to create a custom component button for the DashAgGrid. To have it match the styling of the rest of the site, it would be ideal to create it as a Mantine button or a Material button. Since the dashAgGridComponentFunctions.js is not a module I cannot do the following:

import Button from '@material-ui/core/Button';

dagcomponentfuncs.CustomButton = function (props) {
    ...
    return React.createElement( Button ...)
}

Is there some way of achieving this? Any help would be appreciated. Thank you!

Using "valueFormatter" does not work in a callback

I am using version 2.0.0a4.

I have a table that may change based on a variety of inputs. If I pass the table directly to the layout, it works fine. However, if I try to pass the 'columnDefs' as an output in a callback the table renders but the anything used for valueFormatter is ignored

"undefined" values of markdown columns during grouping

If table contains columns with cellRenderer="markdown" these columns show "undefined" values in group headers regardless of which columns are used for grouping.

Code snippet:

import dash_ag_grid as dag
import pandas as pd
from dash import Dash, html


app = Dash(__name__)

df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)

columnDefs = [
    {"field": "country", "rowGroup": True, "hide": True},
    {"field": "sport"},
    {"field": "year"},
    {"field": "markdown_link", "cellRenderer": "markdown"},
    {"field": "html_link", "cellRenderer": "markdown"},
    {"field": "age"},
]

rows = df.to_dict("records")
for row in rows:
    row["markdown_link"] = "[Markdown Link](https://example.com)"
    row["html_link"] = "<a href='https://example.com'>HTML Link</a>"

app.layout = html.Div(
    [
        dag.AgGrid(
            columnDefs=columnDefs,
            rowData=rows,
            columnSize="sizeToFit",
            defaultColDef={"resizable": True, "sortable": True, "filter": True},
            enableEnterpriseModules=True,
            dangerously_allow_code=True,
        ),
    ],
    style={"margin": 20},
)

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

Result:
image

Using dcc.Link()

Hi,

I have tried a few different way but have not gotten this to work. I'm hoping I missed something simple. Is there any way to add a dcc.Link() to the dashAgGrid as a column or use a callback to achieve the "no refresh" navigation the dcc.Link() provides? This would be very beneficial in a multipage Dash app.

Thank you!

Issue with SizeToFit when default px widths are set in columnDefs (in v2.0.0a2)

I installed v2.0.0a2 and noticed that it broke my table where I had set default column widths in columnDefs and also included columnSize="sizeToFit". In v2.0.0a1 when I did this the table automatically resized and kept the width ratios of the columns but in v2.0.0a2 the table keeps the pixel widths defined in columnDefs and does not resize at all. I rolled back to v2.0.0a1 without changing the code and the behaviour returned to the expected automatic resizing to fit. Just posting here in case it isn't a known issue (maybe an intentional change was made).

Import JS

HI
How can I import JS code to columnDefs?

coin_page_link = """
    params => {
        return '<a target="_blank" href="https://www.tradingview.com/chart/?symbol=BINANCE:' + params.value + '">' +  params.value + '</a>'
        }
    """
columnDefs = [
    {
        "headerName": "Id",
        "field": "id",
        "width": 50,
        "filter": False,
    },
    {
        "headerName": "Buy Time",
        "field": "buy_time",
        "type": "dateColumn",
        "minWidth": 150,
    },
    {
        "headerName": "Symbol",
        "field": "symbol",
        "cellRenderer": coin_page_link
    },]

Version/revision sync / docs / getting started

Hi,

Might be good to have a way to automatically update the revision / versions from one location so everything stays in sync.

Getting started :
pip install dash-ag-grid==2.0.0a3

Warning banner:
2.0.0a3

header upper right 2.0.0a4
image

Clearing rows of a grid with infinite row model

When rendering filtered data in an ag grid with the inifinite row model, the grid contains stale rows that ought to be removed when changing data filters. E.g. consider the following scenario:

  • the grid contains ten rows loaded via infinite row model
  • the user updates its data filters (the filters are other dash components)
  • scrolling through the table, the grid still contains the previously loaded ten rows (some of which might no longer be matched by the new data filters)

I tried the naive approach of setting rowData to an empty list when the filter dash input changes:

@app.callback(
    dash.dependencies.Output("data-grid", "rowData"),
    dash.dependencies.Input('data-filter', 'value'), 
)
def update_rowdata(*_):
    """Clear rowData when one of the filters change, otherwise the table contains stale rows."""
    if not dash.ctx.triggered_id:
        return dash.no_update  # If callback wasn't triggered by input, ignore.

    return []

But rowData isn't available for grids with rowModelType='infinite'. This callback throws the error (warning: long):

this.clientSideRowModel is undefined
(This error originated from the built-in JavaScript code that runs Dash apps. Click to see the full stack trace or open your browser's console.)

7351/e.prototype.setRowData@http://127.0.0.1:8050/_dash-component-suites/dash_ag_grid/async-community.js:2:640824

7351/e.prototype.__setProperty@http://127.0.0.1:8050/_dash-component-suites/dash_ag_grid/async-community.js:2:637400

7351/e.processOnChange/<@http://127.0.0.1:8050/_dash-component-suites/dash_ag_grid/async-community.js:2:133335

7351/e.processOnChange@http://127.0.0.1:8050/_dash-component-suites/dash_ag_grid/async-community.js:2:133270

3920/t.prototype.processChanges/<@http://127.0.0.1:8050/_dash-component-suites/dash_ag_grid/async-community.js:2:1106407

3920/t.prototype.processWhenReady@http://127.0.0.1:8050/_dash-component-suites/dash_ag_grid/async-community.js:2:1106488

3920/t.prototype.processChanges@http://127.0.0.1:8050/_dash-component-suites/dash_ag_grid/async-community.js:2:1106355

3920/t.prototype.processPropsChanges@http://127.0.0.1:8050/_dash-component-suites/dash_ag_grid/async-community.js:2:1105835

3920/t.prototype.componentDidUpdate@http://127.0.0.1:8050/_dash-component-suites/dash_ag_grid/async-community.js:2:1105701

commitLifeCycles@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:19970:24

commitLayoutEffects@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:22938:25

callCallback@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:182:16

invokeGuardedCallbackDev@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:231:18

invokeGuardedCallback@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:286:33

commitRootImpl@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:22676:32

unstable_runWithPriority@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:2685:14

runWithPriority$1@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:11174:12

commitRoot@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:22516:22

finishSyncRender@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:21942:15

performSyncWorkOnRoot@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:21928:25

flushSyncCallbackQueueImpl/<@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:11224:26

unstable_runWithPriority@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:2685:14

runWithPriority$1@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:11174:12

flushSyncCallbackQueueImpl@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:11219:26

flushSyncCallbackQueue@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:11207:5

batchedUpdates$1@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:21997:9

notify@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:11550:12

notifyNestedSubs@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:11610:15

handleChangeWrapper@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:11614:20

dispatch@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:76043:7

./node_modules/redux-thunk/es/index.js/createThunkMiddleware/middleware/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:75713:16

applyProps@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1584:15

./src/observers/executedCallbacks.ts/observer/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1617:40

forEach@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:81428:7

./node_modules/ramda/es/internal/_checkForMethod.js/_checkForMethod/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:83578:119

f2@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:83834:14

./src/observers/executedCallbacks.ts/observer/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1607:55

forEach@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:81428:7

./node_modules/ramda/es/internal/_checkForMethod.js/_checkForMethod/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:83578:119

f2@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:83834:14

observer@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1593:51

./src/StoreObserver.ts/StoreObserver/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:355:9

forEach@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:81428:7

./node_modules/ramda/es/internal/_checkForMethod.js/_checkForMethod/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:83578:119

f2@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:83834:14

./src/StoreObserver.ts/StoreObserver/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:353:51

dispatch@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:76043:7

./node_modules/redux-thunk/es/index.js/createThunkMiddleware/middleware/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:75713:16

_callee$@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1823:25

tryCatch@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1760:2404

./src/observers/executingCallbacks.ts/_regeneratorRuntime/wrap/generator._invoke@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1760:1972

./src/observers/executingCallbacks.ts/_regeneratorRuntime/defineIteratorMethods/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1760:3255

asyncGeneratorStep@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1764:103

_next@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1765:212

promise callback*asyncGeneratorStep@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1764:242

_next@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1765:212

./src/observers/executingCallbacks.ts/_asyncToGenerator/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1765:369

./src/observers/executingCallbacks.ts/_asyncToGenerator/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1765:97

./src/observers/executingCallbacks.ts/observer/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1834:22

forEach@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:81428:7

./node_modules/ramda/es/internal/_checkForMethod.js/_checkForMethod/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:83578:119

f2@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:83834:14

observer@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1790:51

./src/StoreObserver.ts/StoreObserver/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:355:9

forEach@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:81428:7

./node_modules/ramda/es/internal/_checkForMethod.js/_checkForMethod/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:83578:119

f2@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:83834:14

./src/StoreObserver.ts/StoreObserver/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:353:51

dispatch@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:76043:7

./node_modules/redux-thunk/es/index.js/createThunkMiddleware/middleware/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:75713:16

_callee2$@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:2036:25

tryCatch@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1959:2404

./src/observers/prioritizedCallbacks.ts/_regeneratorRuntime/wrap/generator._invoke@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1959:1972

./src/observers/prioritizedCallbacks.ts/_regeneratorRuntime/defineIteratorMethods/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1959:3255

asyncGeneratorStep@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1967:103

_next@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1968:212

./src/observers/prioritizedCallbacks.ts/_asyncToGenerator/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1968:369

./src/observers/prioritizedCallbacks.ts/_asyncToGenerator/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:1968:97

observer@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:2092:24

./src/StoreObserver.ts/StoreObserver/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:355:9

forEach@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:81428:7

./node_modules/ramda/es/internal/_checkForMethod.js/_checkForMethod/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:83578:119

f2@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:83834:14

./src/StoreObserver.ts/StoreObserver/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:353:51

dispatch@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:76043:7

./node_modules/redux-thunk/es/index.js/createThunkMiddleware/middleware/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:75713:16

_callee$@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:2330:23

tryCatch@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:2116:2404

./src/observers/requestedCallbacks.ts/_regeneratorRuntime/wrap/generator._invoke@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:2116:1972

./src/observers/requestedCallbacks.ts/_regeneratorRuntime/defineIteratorMethods/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:2116:3255

asyncGeneratorStep@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:2120:103

_next@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:2121:212

promise callback*asyncGeneratorStep@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:2120:242

_next@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:2121:212

./src/observers/requestedCallbacks.ts/_asyncToGenerator/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:2121:369

./src/observers/requestedCallbacks.ts/_asyncToGenerator/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:2121:97

observer@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:2347:24

./src/StoreObserver.ts/StoreObserver/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:355:9

forEach@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:81428:7

./node_modules/ramda/es/internal/_checkForMethod.js/_checkForMethod/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:83578:119

f2@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:83834:14

./src/StoreObserver.ts/StoreObserver/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:353:51

dispatch@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:76043:7

./node_modules/redux-thunk/es/index.js/createThunkMiddleware/middleware/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:75713:16

dispatch@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:76437:28

_callee$@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:5057:23

tryCatch@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:4946:2404

./src/actions/index.js/_regeneratorRuntime/wrap/generator._invoke@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:4946:1972

./src/actions/index.js/_regeneratorRuntime/defineIteratorMethods/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:4946:3255

asyncGeneratorStep@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:4947:103

_next@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:4948:212

./src/actions/index.js/_asyncToGenerator/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:4948:369

./src/actions/index.js/_asyncToGenerator/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:4948:97

./src/actions/index.js/notifyObservers/<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:5066:20

./node_modules/redux-thunk/es/index.js/createThunkMiddleware/middleware/</<@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:75709:18

setProps@http://127.0.0.1:8050/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_8_1m1677594669.dev.js:3352:32

87781/B/C<@http://127.0.0.1:8050/_dash-component-suites/dash/dcc/async-dropdown.js:2:4256

value@http://127.0.0.1:8050/_dash-component-suites/dash/dcc/async-dropdown.js:2:30660

value@http://127.0.0.1:8050/_dash-component-suites/dash/dcc/async-dropdown.js:2:31433

11622/value/<@http://127.0.0.1:8050/_dash-component-suites/dash/dcc/async-dropdown.js:2:31098

callCallback@http://127.0.0.1:8050/_dash-component-suites/dash/deps/[email protected]_8_1m1677594670.14.0.js:12625:14

The ag grid docs state under Changing the Datasource:

Changing the datasource after the grid is initialised will reset the infinite scrolling in the grid. This is useful if the context of your data changes, i.e. if you want to look at a different set of data.

If a dash callback could change the datasource of the grid, then the grid should reset its rows. However, setting the datasource from a dash callback currently isn't supported by dash-ag-grid (afaik). Perhaps setting the datasource directly isn't required here, but a clear rows (or equivalent) dash output would be welcomed in dash-ag-grid. Maybe there are other ways to clear a grid with the infinite row model in dash-ag-grid?

As a tangent: the dash-ag-grid docs lists infinite scroll under Enterprise features, while the ag grid docs lists the infinite row model as a community feature. Are the dash-ag-grid docs incorrect?

Feature Request add `sizeColumnsToFit` prop

Currently when columnSize="sizeToFit" is set and you change the screen size, the only way to redo the sizeToFit is to refresh the screen.

It would be great to have a sizeColumnsToFit prop so it's possible to call this AG Grid function from a a Dash callback. It would make it possible to have a "size to fit" button.

demo stock portfolio app not working

It errors out with this message all the time when loading:
Invalid prop for this component
Property "selectedRows" was used with component ID: "portfolio-grid" in one of the Input items of a callback. This ID is assigned to a dash_ag_grid.AgGrid component in the layout, which does not support this property. This ID was used in the callback(s) for Output(s): candlestick.figure
all relevant python packages for this demo app are with latest release already.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.