Create tree in angular-grid (ag-grid) with loading async data

I am trying to use angular-grid (ag-grid) to display a tree, as in the example presented in the documentation:

http://www.angulargrid.com/example-file-browser/index.php

In this example, all data has already been provided. How to use asynchronous data loading when expanding a group of rows? I assume that I need to write my own rendering of group strings.

+5
source share
3 answers

I recently came up with the same problem in my React.js application and found a solution. This is similar to what was posted in @leden, but I found a solution on how to maintain current row extensions between updating table rows.

The solution is this:

  • Add a dummy child row for each top level row. May be empty or may have loading ... rows, for example, in the first column.

  • In the case of the getNodeChildDetails event, which is raised each time the rowData table is updated, you can specify whether to expand the row or not. Therefore, the idea is that we are tracking what has expanded and what is not.

    getNodeChildDetails = (rowItem) => { if (rowItem.children) { return { group: true, expanded: rowItem.id in this.expandedRows, children: rowItem.children, }; } else { return null; } }; 
  • In rowGroupOpened, we keep track of which rows will be expanded.

     rowGroupOpened = (param) => { const id= param.node.data.id; if(!param.node.expanded) { delete this.expandedRows[id]; return; } this.expandedRows[id] = true; if (param.node.data.children.length !== 1) { // Here we need to check if only dummy row is present return; } this.api.showLoadingOverlay(); // Here I simulate fetching data from server setTimeout(() => { this.rowData.forEach((e) => { if (e.id == id) { e.children = [ // Add fetch rows ] } }); this.api.setRowData(this.rowData); // Setting data, will trigger getNodeChildDetails call on each row this.api.hideOverlay(); }, 1000); }; 
+3
source

The grid does not support lazy loading of tree data out of the box. So yes, for this you need to write your own cellRenderer.

PS I am the author of ag-Grid, so you can accept this answer as the gospel!

+2
source

Just an idea, but I think that you could add one child placeholder string to the group with "loading ..." in the first cell, with the onRowGroupOpened group event to do ajax to get data from the server, with onreadystatechange , then adding new lines and replacing it. The initial placeholder string may contain the totals calculated by the server to assign the total (cumulative) value in the cells of the group rows that remain unchanged when the real data replaces the placeholder.

I came up with a basic test approach. This is not ideal, as the grid is restored after each extension (I cannot find an elegant way to just add new lines), but it works.

At the very top of the script is an AJAX request for details. Although this happens later in the stream, I put it at the top, so if the server receives this request, it provides data and exits without loading the page again. Alternatively, you can simply put it in another file.

 <?php if (isset($_REQUEST['g'])) { // this is the AJAX request for child data (called later, but needed at the start of the script) // get connection to database require_once 'db_connection.php'; $dbh=getConnection(); // query data to array $sql="SELECT accounts.description AS account, '' AS info, tx.amnt AS amount, 1 AS transactions FROM tx INNER JOIN accounts ON tx.account=accounts.account_id WHERE accounts.description='".$_REQUEST['g']."'"; $data=array(); $result = $dbh->query($sql); while ($row = $result->fetch_assoc()) { $data[]=$row; } $result->free(); // return data as JSON print json_encode($data, JSON_NUMERIC_CHECK); exit; } ?> 

Then immediately after that a regular HTML page appears with a bit more php in javascript in the head:

 <!DOCTYPE html> <html> <head> <script src="lib/ag-grid-enterprise-master/dist/ag-grid-enterprise.js"></script> <script> // get JSON for initial group-level data from server with a little snippet of php which is called when the page is first loaded var rowData = <?php // get connection to the database require_once 'db_connection.php'; $dbh=getConnection(); // query data to array $sql = "SELECT description AS account, 'loading...' AS info, SUM(tx.amnt) AS amount, COUNT(tx.tx_id) AS transactions FROM accounts INNER JOIN tx ON accounts.account_id=tx.account GROUP BY accounts.account_id"; $data=array(); $result = $dbh->query($sql); while ($row = $result->fetch_assoc()) { $data[]=$row; } $result->free(); // inject the JSON into the javascript assignment to rowData print json_encode($data, JSON_NUMERIC_CHECK); ?>; // (back in javascript again) // event function for when a group is expanded function getChildRows(data) { if (data.node.allLeafChildren) { if (data.node.allLeafChildren.length > 0) { if (data.node.allLeafChildren[0].data.info==="loading...") { // data for this group has not yet been loaded, so make AJAX request for it var xmlHttp=new XMLHttpRequest(); xmlHttp.onreadystatechange=function() { if ((xmlHttp.readyState===4) && (xmlHttp.status === 200)) { // call function to add the new rows to the grid addRecords(JSON.parse(xmlHttp.responseText)); } }; var requestParameters="g="+encodeURIComponent(data.node.key); xmlHttp.open("POST", "index.php", true); // call to this same script xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xmlHttp.send(requestParameters); } } } } function addRecords(data) { var x; var d=new Array(); var acc=data[0].account; for(x in gridOptions.api.inMemoryRowModel.rootNode.allLeafChildren) { if (gridOptions.api.inMemoryRowModel.rootNode.allLeafChildren[x].data.account===acc) { // this is group we are replacing with new data for (x in data) { d.push(data[x]); } } else { // this node is just the data as currently loaded to the grid (no change) d.push(gridOptions.api.inMemoryRowModel.rootNode.allLeafChildren[x].data); } } gridOptions.api.setRowData(d); } // set up the grid (standard stuff) var columnDefs = [ {headerName: "Account", field: "account", rowGroupIndex: 0, cellRenderer: "group", cellRendererParams : {suppressCount: true} }, {headerName: "Info", field: "info"}, {headerName: "Amount", field: "amount", aggFunc:"sum"}, {headerName: "Transactions", field: "transactions", aggFunc:"sum"} ]; var gridOptions = { columnDefs: columnDefs, rowData: rowData, groupSuppressAutoColumn: true, onRowGroupOpened: getChildRows /* event created above */ } document.addEventListener("DOMContentLoaded", function() { var eGridDiv = document.querySelector('#myGrid'); new agGrid.Grid(eGridDiv, gridOptions); }); </script> </head> <body> <div id="myGrid" style="height: 100%;" class="ag-fresh"></div> </body> </html> 

@Niall - any ideas on how to add new lines more elegantly and keep the group extension status?

0
source

All Articles