###### tags: `Angular` `ag-Grid`
# 🌝[T]ag-Grid Drill down
## 需求簡述
SD希望可以在grid上加上`Drill down`的功能(點擊資料,可以展開/收起詳細資料)。
## 資料蒐集
### Kendo
網路上找到的套件`Kendo`,看起來有支援Angular做Detail功能的套件,且有兩種樣板可以選擇。
#### [Detail Row Template](https://www.telerik.com/kendo-angular-ui/components/grid/master-detail/detail-template/)

#### [Master-Detail Grids](https://www.telerik.com/kendo-angular-ui/components/grid/master-detail/)

:::danger
❌現階段不希望多載入一個套件來做這件事,因此就沒有多研究此套件了。
:::
### ag-Grid
#### [Master/Detail](https://www.ag-grid.com/javascript-grid-master-detail/)
A1目前是使用ag-Grid的套件來實現grid的功能,但ag-Grid提供相符SD需求的功能是需要付費的。

:::success
✔必須想辦法以不付費的方式來達到此效果。
:::
## 實現筆記
> **agGrid**
> * onCellClicked()。
> * [Full Width Rows](https://www.ag-grid.com/javascript-grid-full-width-rows/)。
> * HTML+CSS。
:::info
💡要使列(row)為全屏寬度(fullWidth)必須實現isFullWidthCell及提供fullWidthCellRenderer
:::
### isFullWidthCell
使用isFullWidthCell告知哪些列是為全屏寬度的。
> this.gridOptions.api.setRowData(data)後,每列都會跑一次isFullWidthCell。
==balance-list.component.ts==
```typescript
isFullWidthCell = function (rowNode) {
return typeof (rowNode.data.detail) === 'string';
};
```
### fullWidthCellRenderer
提供一個fullWidthCellRenderer,讓grid cellRenderer在進行fullWidth渲染時要使用什麼。
==balance-list.component.ts==
```typescript
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==
```typescript
getRowHeight = function (params) {
if (!params) {
return 30;
}
return params.data.detail ? params.data.count * 30 : 30;
};
```
### onCellClicked
單點擊
==a1-grid.component.ts==
```typescript
this.gridOptions.onCellClicked = (event) => {
this.onCellClicked.emit(event);
};
```
偵測到點擊後,將資料整理成HTML樣式的字串,在這邊就要將詳細資料的畫面準備好。
> CSS世騏學長設計,HTML套世騏學長提供。
==balance-list.component.ts==
```typescript
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);
}
```