Develop Note by J.S.

[Datagrid] ag-grid (with Vue3.x, Typescript) 본문

FrontEnd/Datagrid

[Datagrid] ag-grid (with Vue3.x, Typescript)

js-web 2023. 7. 6. 14:16
반응형

Datagrid 기능을 제공하는 모듈 중 ag-grid의 소개 및 사용법입니다. 

 

Datagrid란?
데이터를 가져와 그리드에 배열하도록 하는 JavaScript UI 컴포넌트입니다. 데이터 그리드를 사용하면  정렬, 필터링, 페이징 및 스크롤과 같이 데이터 또는 데이터 표시 속성을 조작하는 기능을 추가할 수 있습니다.

 

또한 Datagrid의 큰 장점으로는 Keyboard Interaction 이 가능합니다. undo, redo, copy & paste, 화살표 이동, page up & down 등 Datagrid에 포커스만 있다면 키보드 조작으로 Excel과 동일한 액션이 가능합니다.

 

ag-grid는 Javascript 기반 오픈소스 Datagrid입니다. 다양한 옵션들을 활성/비활성화 하며 컨트롤 할 수 있고, https://www.ag-grid.com 에서 Document에는 각 기능별 sample과 프레임워크별 sample code를 제공하여 원하는 기능을 쉽게 구현 할 수 있습니다.

 

 

 

<Price>

ag-grid는 무료 community 버전에도 다양한 기능을 제공하며, enterprise는Only Trial 버전으로만 제공됩니다.  공식 홈페이지 Document에서 붉은색 알파벳 'e' 로 표시하고 있습니다. 

 

 

 

 


Grid Test  Sample

1. 모듈 설치 

$npm install ag-grid-vue3 ag-grid-community ag-grid-enterprise --save

2. Import

import { onMounted, ref } from 'vue'
import { AgGridVue } from 'ag-grid-vue3' // Vue3 AgGrid Component
import type { GridApi } from 'ag-grid-community/dist/lib/gridApi'
import type { ColumnApi } from 'ag-grid-community/dist/lib/columns/columnApi'
import type { GridOptions, ColDef } from 'ag-grid-community'

import 'ag-grid-enterprise' // enterprise 기능 사용 시 import
import 'ag-grid-community/styles/ag-grid.css' // 그리드 기본 css
import 'ag-grid-community/styles/ag-theme-alpine.css' // 그리드 테마

'ag-grid-community/styles/ag-theme-alpine.css' 의 경우 Datagrid의 기본 테마를 설정합니다. 

  • ag-theme-alpine : 대비가 높고 패딩이 넉넉한 현대적인 테마입니다.
  • ag-theme-alpine-dark : alpine의 Dark 버전 테마입니다.
  • ag-theme-balham : 전문적인 데이터 사용량이 많은 애플리케이션을 위한 테마입니다.
  • ag-theme-balham-dark : balham의 Dark 버전 테마입니다.
  • ag-theme-material : Google Material Language Specs에 따라 설계된 테마입니다.

테마 적용 방법은 필요한 테마의 css파일을 Import 시킨 뒤 ag-grid-vue Tag의 Class로 테마명을 주면 설정할 수 있습니다. Dark 테마의 경우 일반 테마 파일을 Import 한 뒤 Class명 뒤에 '-dark' 를 추가하여 적용할 수 있습니다.

<template>
	<ag-grid-vue
        style="width: 800px"
        class="ag-theme-alpine-dark"
        :gridOptions="gridOptions"
        @grid-ready="onGridReady"
        @cellClicked="onCellClicked"
    >
	</ag-grid-vue>
</template>
import { onMounted, ref } from 'vue'
import { AgGridVue } from 'ag-grid-vue3' // Vue3 AgGrid Component
import type { GridApi } from 'ag-grid-community/dist/lib/gridApi'
import type { ColumnApi } from 'ag-grid-community/dist/lib/columns/columnApi'
import type { GridOptions, ColDef } from 'ag-grid-community'
import 'ag-grid-enterprise' // enterprise 기능 사용 시 import
import 'ag-grid-community/styles/ag-grid.css' // 그리드 기본 css
import 'ag-grid-community/styles/ag-theme-alpine.css' // 그리드 테마
</script>

 

Grid Theme Documents : https://www.ag-grid.com/javascript-data-grid/themes/#applying-a-theme-to-an-app

 

JavaScript Data Grid: Themes

The grid is styled with CSS, and a theme is simply a CSS class that applies styles to the grid. Download v30 of the best JavaScript Data Grid in the world now.

www.ag-grid.com

3. gridOptions 

event를 제외한 대부분의 Datagrid 기능은 gridOptions에서 활성화 및 정의하여 사용할 수 있습니다.

const gridOptions: GridOptions  = {
  columnDefs: columnDefs, // column 정의
  enableCharts: true, // chart 노출
  rowSelection: 'multiple', // row selection
  // rowMultiSelectWithClick: true, // 클릭으로 row 다중 선택
  enableRangeSelection: true, // 범위 선택가능
  // enableFillHandle: true, // 채우기 handler (ex. excel 자동채우기)
  undoRedoCellEditing: true, // undo 가능
  undoRedoCellEditingLimit: 10, // 최대 undo 횟수
  stopEditingWhenCellsLoseFocus: true, // focus 잃었을때 갱신
  //domLayout: 'autoHeight', // height 자동조정
  rowHeight: 45, // 행 높이
  defaultColDef: {
    editable: true, // 셀 수정 가능
    filter: true // filter 가능
  },
  sideBar: { // 사이드,바
    toolPanels: ['columns', 'filters'],
    defaultToolPanel: '' //기본 노출 sideBar
  },
  processDataFromClipboard: autoAddRows // 붙여넣기 event Handler
}

Grid Options Documents : https://www.ag-grid.com/javascript-data-grid/grid-options/

 

JavaScript Data Grid: Grid Options

All of these grid options are available through the generic GridOptions<TData> interface. Download v30 of the best JavaScript Data Grid in the world now.

www.ag-grid.com

- Column Definition

interface FruitbuyingCount {
  apple: number
  banana: number
  melon: number
}

const columnDefs: ColDef<FruitbuyingCount>[] = [
  {
    headerName: 'index',
    valueGetter: (value) => value.node?.rowIndex + 1, // value handler
    sortable: true,
    editable: false,
    cellStyle: { border: 'none !important' },
    headerCheckboxSelection: true // check box 전체선택
  },
  {
    headerName: 'Apple',
    field: 'apple',
    valueGetter: (value) => (value.data?.apple === null ? 0 : Number(value.data?.SB))
  },
  {
    headerName: 'Banana',
    field: 'banana',
    valueGetter: (value) => (value.data?.banana === null ? 0 : Number(value.data?.BB))
  },
  {
    headerName: 'Melon',
    field: 'melon',
    valueGetter: (value) => (value.datamelonAnte === null ? 0 : Number(value.data?.Ante))
  }
]

4. Event

ag-grid Event 의 경우 @EventName="EventHandler" 형식으로 사용할 수 있습니다.

<template>
    <ag-grid-vue
        style="width: 800px; height: 100%"
        class="ag-theme-alpine"
        :gridOptions="gridOptions"
        @grid-ready="onGridReady"
        @cellClicked="onCellClicked"
    >
    </ag-grid-vue>
</template>
<script setup lang="ts">
...
const gridApi = ref<GridApi | null>(null)
const columnApi = ref<ColumnApi | null>(null)

function onGridReady(params) {
  //그리드 준비완료 이벤트
  gridApi.value = params.api
  columnApi.value = params.columnApi
  
  const rowData: FruitbuyingCount[] = [{ apple: 0, banana: 0, melon: 0 }]
  gridApi.value?.setRowData(rowData)
  gridApi.value?.sizeColumnsToFit()
}
function onCellClicked(params) {
  // 셀 클릭 이벤트
  console.log('cell click : ', params.value)
}
</script>

Grid Event Documents : https://www.ag-grid.com/javascript-data-grid/grid-events/

 

JavaScript Data Grid: Grid Events

This is a list of the events that the grid raises. Download v30 of the best JavaScript Data Grid in the world now.

www.ag-grid.com

5. API

ag-grid에서는 Grid API, Column API를 제공합니다. 

<template>
  <div id="gridDiv">
    <div class="button">
      <button @click="gridApi?.undoCellEditing()">undo</button> //undo api 호출
      <button @click="gridApi?.redoCellEditing()">redo</button> //redo api 호출
      <button @click="update">update</button>
    </div>
</template>
<script setup lang="ts">
...
function clearSelectedNode() {
  // 범위 지정된(선택된) 셀 clear
  gridApi.value?.clearFocusedCell()
  gridApi.value?.clearRangeSelection()
}

onMounted(() => {
  const body = document.body
  body.addEventListener('mouseup', (e: Event) => {
    // out focus event
    let gridDiv = document.querySelector('#gridDiv')
    if (!gridDiv.contains(e.target as HTMLDivElement)) {
      //grid 외부 선택시
      clearSelectedNode()
    }
  })
})
</script>

Grid API Documents : https://www.ag-grid.com/javascript-data-grid/grid-api/

 

JavaScript Data Grid: Grid API

All of these grid methods are available through the api property of GridOptions . Download v30 of the best JavaScript Data Grid in the world now.

www.ag-grid.com

Column API Documents : https://www.ag-grid.com/javascript-data-grid/column-api/

 

JavaScript Data Grid: Column API

Below are listed all the column API methods. Download v30 of the best JavaScript Data Grid in the world now.

www.ag-grid.com

5. 코드 전문

더보기
<template>
  <div id="gridDiv">
    <div class="button">
      <button @click="gridApi?.undoCellEditing()">undo</button>
      <button @click="gridApi?.redoCellEditing()">redo</button>
      <button @click="update">update</button>
    </div>
    <div style="height: 700px; overflow: auto">
      <ag-grid-vue
        style="width: 800px; height: 100%"
        class="ag-theme-alpine"
        :gridOptions="gridOptions"
        @grid-ready="onGridReady"
        @cellClicked="onCellClicked"
      >
      </ag-grid-vue>
    </div>
    <div class="button">
      <button @click="onAddRow">추가</button>
      <button @click="onRemoveSelected">삭제</button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { AgGridVue } from 'ag-grid-vue3'
import type { GridApi } from 'ag-grid-community/dist/lib/gridApi'
import type { ColumnApi } from 'ag-grid-community/dist/lib/columns/columnApi'
import type { GridOptions, ColDef } from 'ag-grid-community'
import 'ag-grid-enterprise'
import 'ag-grid-community/styles/ag-grid.css'
import 'ag-grid-community/styles/ag-theme-alpine.css'

const gridApi = ref<GridApi | null>(null)
const columnApi = ref<ColumnApi | null>(null)

interface FruitbuyingCount {
  apple: number
  banana: number
  melon: number
}

const columnDefs: ColDef<FruitbuyingCount>[] = [
  {
    headerName: 'index',
    valueGetter: (value) => value.node?.rowIndex + 1, // value handler
    sortable: true,
    editable: false,
    cellStyle: { border: 'none !important' },
    headerCheckboxSelection: true // check box 전체선택
  },
  {
    headerName: 'Apple',
    field: 'apple',
    valueGetter: (value) => (value.data?.apple === null ? 0 : Number(value.data?.SB))
  },
  {
    headerName: 'Banana',
    field: 'banana',
    valueGetter: (value) => (value.data?.banana === null ? 0 : Number(value.data?.BB))
  },
  {
    headerName: 'Melon',
    field: 'melon',
    valueGetter: (value) => (value.datamelonAnte === null ? 0 : Number(value.data?.Ante))
  }
]
const gridOptions: GridOptions = {
  columnDefs: columnDefs,
  enableCharts: true, // chart 노출
  rowSelection: 'multiple', // row selection
  // rowMultiSelectWithClick: true, // 클릭으로 row 다중 선택
  enableRangeSelection: true, // 범위 선택가능
  // enableFillHandle: true, // 채우기 handler
  undoRedoCellEditing: true, // undo 가능
  undoRedoCellEditingLimit: 10, // 최대 undo 횟수
  stopEditingWhenCellsLoseFocus: true, // focus 잃었을때 갱신
  // domLayout: 'autoHeight', // height 자동조정
  rowHeight: 45, // 행 높이
  defaultColDef: {
    editable: true, // 셀 수정 가능
    filter: true // filter 가능
  },
  // 사이드,바
  sideBar: {
    toolPanels: ['columns', 'filters'],
    defaultToolPanel: ''
  },
  processDataFromClipboard: autoAddRows
}
function getAllNode() {
  let rowData = []
  gridApi.value?.forEachNode((node) => rowData.push(node.data))
  return rowData
}
function update() {
  // action에 의한 api 전송 시 그리드 전체 데이터 가져오기
  console.log(getAllNode())
}
function onGridReady(params) {
  //그리드 준비완료 이벤트'
  gridApi.value = params.api
  columnApi.value = params.columnApi

  const rowData: FruitbuyingCount[] = [{ apple: 0, banana: 0, melon: 0 }]
  gridApi.value?.setRowData(rowData)
  gridApi.value?.sizeColumnsToFit()
}
function onCellClicked(params) {
  // 셀 클릭 이벤트
  console.log('cell click : ', params.value)
}
function clearSelectedNode() {
  // 범위 지정된(선택된) 셀 clear
  gridApi.value?.clearRangeSelection()
  gridApi.value?.clearFocusedCell()
}
function onAddRow() {
  // row추가
  const newItem = [{ SB: 0, BB: 0, Ante: 0 }]
  gridApi.value?.applyTransaction({ add: newItem })
  clearSelectedNode()
}
function onRemoveSelected() {
  // row 삭제
  const id = gridApi.value?.getFocusedCell() //focus된 셀 가져오기
  console.log(id)
  let rows = getAllNode()
  if (rows.length == 1) return
  if (id) {
    // 선택된 셀이 있으면 그 셀이 포함된 row 삭제
    rows.splice(id.rowIndex, 1)
  } else {
    // 아닌경우 마지막 셀 삭제
    rows.splice(rows.length - 1, 1)
  }
  gridApi.value?.setRowData(rows) // set row data
  gridApi.value?.sizeColumnsToFit() //width 폭 맞춤
  clearSelectedNode()
}

function autoAddRows(params) {
  const emptyLastRow =
    params.data[params.data.length - 1][0] === '' &&
    params.data[params.data.length - 1].length === 1

  if (emptyLastRow) {
    params.data.splice(params.data.length - 1, 1)
  }

  const lastIndex = gridApi.value?.getModel().rowsToDisplay.length - 1
  const focusedCell = gridApi.value?.getFocusedCell()
  const focusedIndex = focusedCell.rowIndex

  if (focusedIndex + params.data.length - 1 > lastIndex) {
    const resultLastIndex = focusedIndex + (params.data.length - 1)
    const addRowCount = resultLastIndex - lastIndex
    console.log(addRowCount)
    let rowsToAdd = []
    let addedRows = 0
    let currIndex = params.data.length - 1
    while (addedRows < addRowCount) {
      rowsToAdd.push(params.data.splice(currIndex, 1)[0])
      addedRows++
      currIndex--
    }
    rowsToAdd = rowsToAdd.reverse()
    let newRowData = []
    rowsToAdd.map((r) => {
      console.log(r)
      let row = {}
      let currColumn = focusedCell.column
      r.map((i) => {
        if (currColumn.hasOwnProperty('colDef')) {
          row[currColumn.colDef.field] = i
          currColumn = columnApi.value?.getDisplayedColAfter(currColumn)
        }
      })
      newRowData.push(row)
    })
    console.log(newRowData)
    gridApi.value?.applyTransaction({ add: newRowData })
  }
  return params.data
}

onMounted(() => {
  const body = document.body
  body.addEventListener('mouseup', function (e: Event) {
    // out focus event
    let gridDiv = document.querySelector('#gridDiv')
    if (!gridDiv.contains(e.target as HTMLDivElement)) {
      //grid 외부 선택시
      clearSelectedNode()
    }
  })
})
</script>

<style scoped lang="scss">
.button {
  text-align: end;
  button {
    width: 100px;
    height: 40px;
  }
}
</style>

6. ETC

이외에도 ag-grid에서는 많은 기능을 제공하고 있습니다. 
1) Chart 

https://www.ag-grid.com/examples/integrated-charts-chart-tool-panels/omitting-ordering-tool-panels/packages/vanilla/index.html

 

JavaScript example

 

www.ag-grid.com

2) Filter

https://www.ag-grid.com/examples/filter-multi/floating-filters/packages/vanilla/index.html

 

JavaScript example

 

www.ag-grid.com

3) SideBar

https://www.ag-grid.com/examples/side-bar/fine-tuning/packages/vanilla/index.html

 

JavaScript example

 

www.ag-grid.com

4) Import & Export

import

https://www.ag-grid.com/examples/excel-import/excel-import/packages/vanilla/index.html

 

JavaScript example

 

www.ag-grid.com

export

https://www.ag-grid.com/examples/csv-export/csv-export/packages/vanilla/index.html

 

JavaScript example

Show CSV export content text Download CSV export file

www.ag-grid.com

5) Grouping

https://www.ag-grid.com/examples/grouping/default-row-grouping/packages/vanilla/index.html

 

JavaScript example

 

www.ag-grid.com

6) Demo

https://www.ag-grid.com/example/

 

Data Grid: AG Grid: Demo of high performance datagrid

AG Grid is a feature-rich datagrid available in Community or Enterprise versions. Download v30 of the best Data Grid in the world now.

www.ag-grid.com

 

 

참고사이트

https://www.ag-grid.com/

https://velog.io/@cjh951114/VueAG-Grid-AG-Grid-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0

https://dong-queue.tistory.com/57

https://dev.grapecity.co.kr/bbs/board.php?bo_table=wijmo_bntips&wr_id=110 

 

반응형

'FrontEnd > Datagrid' 카테고리의 다른 글

[Datagrid] Datagrid 종류 및 특징  (0) 2023.07.10