AG Grid Community
CI4 JSON API와 AG Grid Community를 연동하여 정렬·필터·페이지네이션·서버사이드 처리를 구현합니다.
클라이언트 사이드 모드
전체 데이터를 한 번에 로드합니다. 정렬·필터·페이지네이션은 브라우저에서 처리됩니다.
선택된 행 상세
서버 사이드 모드 (Infinite Row Model)
데이터를 청크 단위로 서버에서 요청합니다. 대용량 데이터에 적합하며 정렬도 서버에서 처리됩니다.
1
CDN 설정 (API 키 불필요)
<!-- AG Grid Community — jsDelivr CDN, 무료 오픈소스 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ag-grid-community@33/styles/ag-grid.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ag-grid-community@33/styles/ag-theme-quartz.min.css">
<script src="https://cdn.jsdelivr.net/npm/ag-grid-community@33/dist/ag-grid-community.min.js"></script>
2
클라이언트 사이드 — 전체 데이터 로드
// 컬럼 정의
const colDefs = [
{ field: 'id', headerName: '#', width: 70 },
{ field: 'title', headerName: '제목', flex: 2, filter: true },
{ field: 'author', headerName: '작성자', width: 120 },
{ field: 'views', headerName: '조회수', width: 100,
cellRenderer: p => `<span class="badge">${p.value}</span>` },
{ field: 'created_at', headerName: '작성일', width: 150 },
];
// 그리드 생성
const gridApi = agGrid.createGrid(document.getElementById('my-grid'), {
columnDefs: colDefs,
defaultColDef: { sortable: true, resizable: true },
pagination: true,
paginationPageSize: 10,
rowData: [], // 초기 빈 데이터
});
// CI4 API에서 데이터 로드
fetch('/examples/aggrid/data')
.then(r => r.json())
.then(rows => gridApi.setGridOption('rowData', rows));
3
CI4 — 클라이언트 데이터 API
public function data(): Response
{
$rows = db_connect()
->table('posts')
->select('id, title, author, views, created_at')
->where('deleted_at', null)
->orderBy('id', 'ASC')
->get()
->getResultArray();
return $this->response->setJSON($rows);
}
4
서버 사이드 — Infinite Row Model
let serverSearch = '';
const gridApi = agGrid.createGrid(document.getElementById('server-grid'), {
columnDefs: colDefs,
rowModelType: 'infinite', // 서버 사이드 무한 스크롤
cacheBlockSize: 20, // 한 번에 요청할 행 수
maxBlocksInCache: 5,
datasource: {
getRows(params) {
const url = new URL('/examples/aggrid/server-data', location.origin);
url.searchParams.set('startRow', params.startRow);
url.searchParams.set('endRow', params.endRow);
url.searchParams.set('search', serverSearch);
if (params.sortModel.length) {
url.searchParams.set('sortField', params.sortModel[0].colId);
url.searchParams.set('sortDir', params.sortModel[0].sort);
}
fetch(url)
.then(r => r.json())
.then(data => {
params.successCallback(data.rows, data.total);
})
.catch(() => params.failCallback());
},
},
});
5
CI4 — 서버 사이드 API
public function serverData(): Response
{
$startRow = (int) $this->request->getGet('startRow');
$endRow = (int) $this->request->getGet('endRow');
$sortField = $this->request->getGet('sortField') ?? 'id';
$sortDir = $this->request->getGet('sortDir') ?? 'asc';
$search = trim($this->request->getGet('search') ?? '');
$builder = db_connect()->table('posts')
->where('deleted_at', null);
if ($search) {
$builder->groupStart()
->like('title', $search)
->orLike('author', $search)
->groupEnd();
}
$total = $builder->countAllResults(false); // 전체 수 (페이지 적용 전)
$rows = $builder
->orderBy($sortField, $sortDir)
->limit($endRow - $startRow, $startRow)
->get()->getResultArray();
return $this->response->setJSON([
'rows' => $rows,
'total' => $total,
]);
}