FreeGridv1.1.0한국어

Server-side grouping

Groups with counts and totals from the server, loaded as they open.

Code for this demo

import { createGrid, type Row, type ServerParams } from '@freegridjs/core';
import { makeRows } from '../data';
import { select, separator, text, tr, type DemoContext } from '../ui';

export default function mount(ctx: DemoContext) {
  const { lang } = ctx;
  const h = (en: string, ko: string) => tr(lang, { en, ko });
  const all = makeRows(20000);

  /**
   * A pretend server. With groupBy it answers, for the open groups (groupKeys),
   * one row per group with its count and totals — what a GROUP BY query returns.
   */
  const datasource = {
    getRows(p: ServerParams) {
      const by = p.groupBy ?? [];
      const keys = p.groupKeys ?? [];
      let rows = all.filter(r => keys.every((k, i) => r[by[i]] === k));
      let answer: { rows: Row[]; total?: number };
      if (keys.length < by.length) {
        const col = by[keys.length];
        const groups = new Map<unknown, { count: number; q1: number; total: number }>();
        for (const r of rows) {
          const g = groups.get(r[col]) ?? { count: 0, q1: 0, total: 0 };
          g.count++;
          g.q1 += r.q1;
          g.total += r.total;
          groups.set(r[col], g);
        }
        const desc = p.sort.find(s => s.colId === col)?.dir === 'desc';
        answer = { rows: [...groups].sort((a, b) => String(a[0]).localeCompare(String(b[0])) * (desc ? -1 : 1)).map(([v, g]) => ({ [col]: v, ...g })) };
        ctx.log(`getRows(groupKeys: ${JSON.stringify(keys)}) → ${answer.rows.length} ${h('groups', '그룹')}`);
      } else {
        rows = rows.slice(p.start, p.end);
        answer = { rows, total: rows.length };
        ctx.log(`getRows(groupKeys: ${JSON.stringify(keys)}) → ${rows.length} ${h('rows', '행')}`);
      }
      return new Promise<typeof answer>(resolve => setTimeout(() => resolve(answer), 250));
    },
  };

  const grid = createGrid(ctx.host, {
    columns: [
      { field: 'country', header: h('Country', '국가'), width: 160 },
      { field: 'company', header: h('Company', '회사'), width: 160 },
      { field: 'name', header: h('Name', '이름'), width: 160 },
      { field: 'q1', header: 'Q1', type: 'number', format: '#,##0', width: 130, aggFunc: 'sum' },
      { field: 'total', header: h('Total', '합계'), type: 'number', format: '#,##0', width: 140, aggFunc: 'sum' },
    ],
    datasource, getRowId: r => String(r.id), locale: lang,
    groupBy: ['country', 'company'],
  });

  text(ctx, h('20,000 rows stay on the "server". Opening a group asks only for what is inside it; the log shows each request.',
    '2만 행은 "서버"에만 있습니다. 그룹을 펼칠 때 그 안에 든 것만 요청합니다. 아래 기록에서 요청을 볼 수 있습니다.'));
  separator(ctx);
  select(ctx, h('Group by', '그룹 기준'), [['country,company', h('Country → Company', '국가 → 회사')], ['company', h('Company', '회사')], ['', h('None', '없음')]], 'country,company',
    v => grid.setGroupBy(v ? v.split(',') : []));
  return grid;
}