justpy icon indicating copy to clipboard operation
justpy copied to clipboard

How to use AgGrid API

Open Killitz opened this issue 4 years ago • 18 comments

https://www.ag-grid.com/javascript-grid-data-update-transactions/ hi i'm looking for a guide to use the grid API applyTransaction(transaction) to correctly update the data in my grid. i read your example :https://justpy.io/grids_tutorial/grid_api/ but in this example the functions: self.grid.run_api('selectAll()', msg.page) and self.grid.run_api('deselectAll()', msg.page) don't need any parameter. applyTransaction(transaction) instead need the transaction object, can you show me how to pass it correctly? thanks for the help

Killitz avatar Oct 28 '20 09:10 Killitz

image

Killitz avatar Oct 28 '20 11:10 Killitz

image

Killitz avatar Oct 28 '20 11:10 Killitz

In order for applyTransaction to work, it looks like changes are required in the JavaScript part of the AgGrid component. You can still get the same results by changing the rowData in the grid options on the server side. Is that not a viable option for you?

elimintz avatar Oct 28 '20 20:10 elimintz

image

Killitz avatar Oct 29 '20 08:10 Killitz

it's not the same , look at the example: https://www.ag-grid.com/javascript-grid-data-update-transactions/ the add items button insert new data without losing the selection; changing the rowData directly will delete this information. The difference is explained here: https://www.ag-grid.com/javascript-grid-data-update/#setting-fresh-row-data

Killitz avatar Oct 29 '20 08:10 Killitz

I see. I will add support for this in a future version.

elimintz avatar Oct 29 '20 12:10 elimintz

I too would love this feature. I would like to refresh ag-grid cell values as new (streaming) values arrive. Updating row data redraws the entire table, which leads to a number of undesirable side effects. I have found this easy using Quasar, but it seems impossible using ag-grid as applyTransaction (and similar api methods) are not supported.

othalan avatar Jul 06 '21 20:07 othalan

Below is an example of how I've been interacting with Ag-grid API, particularly with applyTransaction. Using this approach, I've been able to use most (if not all) of the API methods

import justpy as jp

grid_options = {
    'defaultColDef': {
        'filter': True,
    }, 
      'columnDefs': [
      {'headerName': "Make", 'field': "make"},
      {'headerName': "Model", 'field': "model"},
      {'headerName': "Price", 'field': "price"}
    ],
      'rowData': [
      {'make': "Toyota", 'model': "Celica", 'price': 35000},
      {'make': "Ford", 'model': "Mondeo", 'price': 32000},
      {'make': "Porsche", 'model': "Boxter", 'price': 72000}
    ],
}

async def new_row(self, msg):
    wp = msg.page
    new_row = {"make": "Chevy", "model": "Corevette", "price": 42100}
    await wp.run_javascript(f"""cached_grid_def['g' + {wp.grid.id}].api.applyTransaction({{  add: [{new_row}] }})""") 

def grid_test():
    wp = jp.QuasarPage()  
    jp.QBtn(a=wp, icon='fas fa-plus-square', color="light-green-14", click=new_row)
    wp.grid = jp.AgGrid(a=wp, options=grid_options)
    return wp

jp.justpy(grid_test)

rroyer-xyz avatar Jul 07 '21 14:07 rroyer-xyz

Thank you for posting this! Based on your solution I added a new method to the AgGrid class that will be available in the upcoming version. The new_row event handler would then look like this:

async def new_row(self, msg):
    wp = msg.page
    new_row = {"make": "Chevy", "model": "Corevette", "price": 42100}
    transaction = {'add': [new_row]}
    # await wp.run_javascript(f"""cached_grid_def['g' + {wp.grid.id}].api.applyTransaction({{  add: [{new_row}] }})""")
    await wp.grid.apply_transaction(transaction, wp)

If you are doing more things like this, let me know and I will add them as methods to AgGrid.

elimintz avatar Jul 07 '21 14:07 elimintz

I need update functionality. This is slightly more complex as it requires a row node object. I will give a shot at adapting the method suggested by @rroyer-xyz and will post any working code.

The challenge is that grid options will require a function to be defined for getting the row node id as in the below example. @elimintz and others, any suggestions?

const gridOptions = {
    getRowNodeId: (data) => data.id,

    // other grid options ...
}

othalan avatar Jul 07 '21 16:07 othalan

A few notes, questions, and suggestions:

ag-grid version

In case anyone is attempting to test out the above code before a new release, I needed to update ag-grid to a newer version as applyTransaction does not exist in ag-grid 23.0.2. I updated the local copy to ag-grid 25.3.0 with no problems.

Minor code improvement in run_javascript(...) usage

@elimintz: A minor improvement to improve efficiency by better utilizing Python:

Take this line of code from the above example:

    await wp.run_javascript(f"""cached_grid_def['g' + {wp.grid.id}].api.applyTransaction({{  add: [{new_row}] }})""") 

This code can be improved thus:

    await wp.run_javascript(f"""cached_grid_def['g{wp.grid.id}'].api.applyTransaction({{  add: [{new_row}] }})""") 

Same processing time on the server and it saves computation time on the client side. I am happy to submit a PR changing all similar instances in the code base, however it appears you are not keeping development code in GitHub and this would need to happen on the current code base.

othalan avatar Jul 07 '21 18:07 othalan

Below is an example using update functionality and getRowNodeId. The line "wp.grid.evaluate" is needed to set the row id

import justpy as jp

grid_options = {
    'defaultColDef': {
        'filter': True,
    }, 
      'columnDefs': [
      {'headerName': "Make", 'field': "make"},
      {'headerName': "Model", 'field': "model"},
      {'headerName': "Price", 'field': "price"}
    ],
    'getRowNodeId': '''function (data) {
          return data.id;
      }''',      
    'rowData': [
      {'id': 1, 'make': "Toyota", 'model': "Celica", 'price': 35000},
      {'id': 2, 'make': "Ford", 'model': "Mondeo", 'price': 32000},
      {'id': 3, 'make': "Porsche", 'model': "Boxter", 'price': 72000}
    ],
}

async def update_row(self, msg):
    wp = msg.page
    update_rows = [{'id': 1, 'make': "Toyota", 'model': "Celica", 'price': 999},
                  {'id': 2, 'make': "Ford", 'model': "Mondeo", 'price': 888}]
    await wp.run_javascript(f"""cached_grid_def['g' + {wp.grid.id}].api.applyTransaction({{  update: {update_rows} }})""") 

def grid_test():
    wp = jp.QuasarPage()  
    jp.QBtn(a=wp, icon='fas fa-plus-square', color="light-green-14", click=update_row)
    wp.grid = jp.AgGrid(a=wp, options=grid_options)
    wp.grid.evaluate = ['getRowNodeId']     
    return wp

jp.justpy(grid_test)

rroyer-xyz avatar Jul 07 '21 18:07 rroyer-xyz

Thanks again. This looks like it solves the issue of working with node ids. @othalan does this solve your problem?

elimintz avatar Jul 07 '21 19:07 elimintz

Thank you @rroyer-xyz. As it happens, mere seconds before your update I came to the same solution. @elimintz, yes this does solve my problem. It took me awhile to find wp.grid.evaluate.

(NOTE: I posted this comment before, but realized I needed a few changes. So deleted the old comment and added a new version....)

However, as an implementation detail I wonder if there is a better way to provide access to API methods. The proposed new_row method is a very narrow use of the highly flexible ag-grid applyTransaction function.

In a perfect world, it would be nice to have the ag-grid api function calls mirrored in the python api. Perhaps there is a method to automate this via inspection of the javascript code?

Alternatively, rather than providing narrow use case methods such as new_row, perhaps more extensive documentation around using api calls would be sufficient.

Or another alternative, perhaps a more flexible run_api call would be sufficient. Such as this:

    async def run_api(self, page, command, args=None):
        await page.run_javascript(f"cached_grid_def.g{self.id}.api.{command}({','.join([str(x) for x in args or []])})")

Example usage:

await self.run_api(wp, "applyTransaction", {"update": updated_rows_list, "add": new_row_list})

I would need to examine the ag-grid api in more detail to determine if the above is sufficient, but at a quick glance I think it would cover most use cases.

othalan avatar Jul 07 '21 20:07 othalan

Please see https://github.com/elimintz/justpy/issues/158#issuecomment-875674681 above. I added the apply_transaction method to my development version and it will be part of the upcoming version.

elimintz avatar Jul 07 '21 20:07 elimintz

Please see #158 (comment) above. I added the apply_transaction method to my development version and it will be part of the upcoming version.

My apologies, I wasn't thinking straight looking at that comment! I still wonder if API calls in general could be helped about by a bit of more flexible code.

othalan avatar Jul 07 '21 20:07 othalan

No need to apologize. Would be happy to improve the api interface. If you think of something, let me know.

elimintz avatar Jul 07 '21 20:07 elimintz

I will feed back my ideas as I continue development on my project.

othalan avatar Jul 07 '21 20:07 othalan