使用异步数据加载在角网格(ag-grid)中创建树

时间:2015-08-27 06:36:11

标签: angularjs angular-grid

我正在尝试使用角度网格(ag-grid)来显示树,如文档中提供的示例所示:

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

在给定的示例中,已经提供了所有数据。扩展行组时如何使用异步数据加载?我的猜测是我需要编写自己的组行渲染器。

3 个答案:

答案 0 :(得分:4)

我最近在我的React.js应用程序中遇到了同样的问题并找到了解决方案。它与@leden发布的类似,但我找到了解决方案如何维护表行更新之间的当前行扩展。

解决方案如下:

  1. 为每个顶级行添加虚拟子行。可以为空或者可以在第一列中加载...字符串。

  2. 在每次更新表rowData时调用的事件getNodeChildDetails上,您可以指定是否应该扩展行。所以我们的想法是跟踪扩展的内容和不扩展的内容。

    getNodeChildDetails = (rowItem) => {
      if (rowItem.children) {
        return {
          group: true,
          expanded: rowItem.id in this.expandedRows,
          children: rowItem.children,
        };
      }
      else {
        return null;
      }
    };
    
  3. 在事件rowGroupOpened上,我们会跟踪哪些行被展开。

    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);
      };
    

答案 1 :(得分:2)

网格不支持开箱即用的树数据的延迟加载。所以是的,你必须编写自己的cellRenderer来实现这一点。

PS我是ag-Grid的作者,所以你可以把这个答案当成福音!

答案 2 :(得分:0)

只是一个想法,但我认为您可以使用" loading ... "添加一个占位符子行。在第一个单元格中,将组的 onRowGroupOpened 事件设置为进行ajax调用以从服务器获取数据,然后使用 onreadystatechange 然后添加新行并替换占位符一个。初始占位符行可以包含服务器计算的总值,以驱动组行单元格中的聚合(总计)值,当实际数据替换占位符时,这些值将保持不变。

我已经对该方法进行了基本测试。它并不完美,因为网格在每次扩展后重建(我无法找到一种优雅的方式来追加新行),但它确实有用。

在脚本的最顶部是AJAX调用细节。虽然这在流程的后期发生,但我把它放在顶部,这样如果服务器收到此请求,它会提供数据并退出,而不会再次加载页面。或者你可以把它放到另一个文件中。

<?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;
}
?>

然后立即出现一个普通的HTML页面,在头部的javascript中有更多的php:

<!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 - 关于如何更优雅地添加新行并保留群组扩展状态的任何想法?