Try   HackMD
tags: Angular ag-Grid

🌝[T]ag-Grid Drill down

需求簡述

SD希望可以在grid上加上Drill down的功能(點擊資料,可以展開/收起詳細資料)。

資料蒐集

Kendo

網路上找到的套件Kendo,看起來有支援Angular做Detail功能的套件,且有兩種樣板可以選擇。

Detail Row Template

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Master-Detail Grids

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

❌現階段不希望多載入一個套件來做這件事,因此就沒有多研究此套件了。

ag-Grid

Master/Detail

A1目前是使用ag-Grid的套件來實現grid的功能,但ag-Grid提供相符SD需求的功能是需要付費的。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

✔必須想辦法以不付費的方式來達到此效果。

實現筆記

agGrid

💡要使列(row)為全屏寬度(fullWidth)必須實現isFullWidthCell及提供fullWidthCellRenderer

isFullWidthCell

使用isFullWidthCell告知哪些列是為全屏寬度的。

this.gridOptions.api.setRowData(data)後,每列都會跑一次isFullWidthCell。

balance-list.component.ts

isFullWidthCell = function (rowNode) {
    return typeof (rowNode.data.detail) === 'string';
};

fullWidthCellRenderer

提供一個fullWidthCellRenderer,讓grid cellRenderer在進行fullWidth渲染時要使用什麼。

balance-list.component.ts

fullWidthCellRenderer = (params) => {
let cssClass;
// rowPinned 是凍結列的意思
if (params.node.rowPinned) {
  cssClass = 'example-full-width-pinned-row';
} else {
  cssClass = 'example-full-width-row';
}
// Create new DOM element
const eDiv = document.createElement('div');
eDiv.innerHTML = `<div class="${cssClass}">${params.data.detail}</div>`;
return eDiv.firstChild;
}

getRowHeight

設定row高度用,可依自己需求指定高度。

balance-list.component.ts

getRowHeight = function (params) {
if (!params) {
  return 30;
}
return params.data.detail ? params.data.count * 30 : 30;
};

onCellClicked

單點擊
a1-grid.component.ts

this.gridOptions.onCellClicked = (event) => {
  this.onCellClicked.emit(event);
};

偵測到點擊後,將資料整理成HTML樣式的字串,在這邊就要將詳細資料的畫面準備好。

CSS世騏學長設計,HTML套世騏學長提供。

balance-list.component.ts

onRowClicked(params) {
    // 詳細資料(Detail)
    /*準備資料 #依點擊Type & ReasonName為依據*/
    const rowData: BalanceList = params.data;
    const rowDetail = this.balanceList.filter(item => item.Type == rowData.Type && item.ReasonName == rowData.ReasonName && !!item.BShortName);
    /*資料畫面 #detail:放HTML(畫面+資料) #count:依筆數給高度*/
    const gridData = this.a1Grid.getAllGridData();
    const gridDetail = { detail: '', count: 0};

    /*資料畫面 #身體資料*/
    rowDetail.forEach((detail, i) => {
      /*規格上的TenantAmount = TotalAmount*/
      gridDetail.detail +=
        `<tr>
          <td style="width: 100px;">${detail.BShortName}</td>
          <td style="width: 100px;">${detail.TenantQty}</td>
          <td style="width: 100px;">${this.decimalPipe.transform(detail.TotalAmount, '')}</td>
        </tr>`;
      gridDetail.count = i + 2;
    });

    /*資料畫面 #標題名稱*/
    gridDetail.detail =
    `<table>
      <tbody>
        <tr>
          <th style="width: 100px;">分店簡稱</th>
          <th style="width: 100px;">數量</th>
          <th style="width: 100px;">金額</th>
        </tr>
        ${gridDetail.detail}
      </tbody>
    </table>`;

    // 詳細資料收起|展開
    /*收起*/
    if (gridData[params.rowIndex + 1] && gridData[params.rowIndex + 1].detail) {
      gridData.splice(params.rowIndex + 1, 1);
    } else if (rowDetail.length > 0) {
    /*展開*/
      gridData.splice(params.rowIndex + 1, 0, gridDetail);
    }

    this.a1Grid.setGridRowData(gridData);
  }