2015-08-27 41 views

回答

2

網格不支持延遲加載樹數據。所以是的,你必須編寫自己的cellRenderer來實現這一點。

PS我是ag-Grid的作者,所以你可以把這個答案當作福音!

+0

嘿尼爾,如果我不要求太多,能否請您詳細一點?由於編寫你自己的groupRowRenderer會扔掉很多標準和有用的行爲(擴展,摺疊和所有這些),我在考慮是否有一種侵入性較小的方法。 例如,是否可以將ajax調用onRowExpand?或者節點將沒有子節點(在點擊/嘗試擴展時)將不允許調用「onRowExpand」? – Zubzob

+0

另外,這不會影響虛擬化功能嗎? – Zubzob

+0

沒有看到它會如何影響行虛擬化。如果該組未擴展,則不會考慮這些行進行渲染,因此沒有理由將它們包含在虛擬化中。 –

0

只是一個想法,但我認爲你可以在第一個單元格添加一個佔位符子行到組「載入中...」,同組的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頁面多一點點的PHP的頭在JavaScript中:

<!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 - 如何更優雅添加新行任何想法並保留團隊擴張的狀態?

2

我最近在我的React.js應用程序中遇到了同樣的問題,並找到了解決方案。這與@leden發佈的內容類似,但我發現解決方案如何維護錶行之間的當前行擴展更新。

解決的方法如下:

  1. 添加虛擬子行的每個頂級一行。可以爲空或者可以在第一列中加載...字符串。

  2. 在事件getNodeChildDetails(每當您更新表rowData時調用)時,您可以指定是否應該展開行。所以我們的想法是,我們跟蹤什麼是擴大和什麼不是。

    getNodeChildDetails = (rowItem) => { 
        if (rowItem.children) { 
        return { 
         group: true, 
         expanded: rowItem.id in this.expandedRows, 
         children: rowItem.children, 
        }; 
        } 
        else { 
        return null; 
        } 
    }; 
    
  3. On事件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); 
        };