FreeGridv1.15.1English

트리 데이터

getParentId로 조직도·폴더·자재 명세서를 트리로 보여 주고, 처음 펼칠 때 서버에서 자식을 불러오며, 부모와 자식을 함께 체크합니다.

실행 예제트리 데이터

조직도를 트리로: 부모 아래 행, 펼칠 때 불러오는 자식, 자식까지 함께 체크되는 부모.

이 데모의 코드
import { createGrid, type Row } from '@freegridjs/core';
import { button, 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 });
  // an org chart: departments contain teams, teams contain people
  const org: Row[] = [
    { id: 'hq', parent: null, name: h('Head office', '본사'), role: '', budget: 1200 },
    { id: 'dev', parent: 'hq', name: h('Development', '개발본부'), role: '', budget: 640 },
    { id: 'web', parent: 'dev', name: h('Web team', '웹팀'), role: '', budget: 260 },
    { id: 'p1', parent: 'web', name: '김민준', role: h('Lead', '팀장'), budget: 0 },
    { id: 'p2', parent: 'web', name: '이서연', role: h('Engineer', '개발자'), budget: 0 },
    { id: 'app', parent: 'dev', name: h('App team', '앱팀'), role: '', budget: 380 },
    { id: 'p3', parent: 'app', name: '박지호', role: h('Engineer', '개발자'), budget: 0 },
    { id: 'biz', parent: 'hq', name: h('Business', '사업본부'), role: '', budget: 560 },
    { id: 'p4', parent: 'biz', name: '최유나', role: h('Manager', '매니저'), budget: 0 },
    { id: 'p5', parent: 'biz', name: '정하준', role: h('Sales', '영업'), budget: 0 },
    // its children come from the "server" on first expand
    { id: 'lab', parent: 'hq', name: h('Research lab (loads on expand)', '연구소 (펼칠 때 불러옴)'), role: '', budget: 300, lazy: true },
  ];
  const grid = createGrid(ctx.host, {
    columns: [
      { field: 'name', header: h('Organization', '조직'), width: 280 },
      { field: 'role', header: h('Role', '직책'), width: 140 },
      { field: 'budget', header: h('Budget (M)', '예산(백만)'), type: 'number', format: '#,##0', width: 140 },
    ],
    data: org,
    locale: lang,
    getRowId: r => r.id,
    rowSelection: 'multiple',
    groupSelectsChildren: true,
    groupDefaultExpanded: 1,
    treeData: {
      getParentId: r => r.parent,
      hasChildren: r => !!r.lazy,
      // pretend server: answers after 600 ms
      loadChildren: row => new Promise<Row[]>(resolve => setTimeout(() => resolve([
        { id: 'r1', parent: row.id, name: '한지민', role: h('Researcher', '연구원'), budget: 0 },
        { id: 'r2', parent: row.id, name: '오세훈', role: h('Researcher', '연구원'), budget: 0 },
      ]), 600)),
    },
  });
  grid.on('groupToggle', e => ctx.log(`groupToggle → ${e.key}: ${e.expanded}`));
  grid.on('childrenLoaded', e => ctx.log(`childrenLoaded → ${e.rows.length}`));

  text(ctx, h('Open the arrows and check a department: its people are checked too. Search keeps the parents of every match.',
    '화살표로 펼치고 부서를 체크해 보세요. 소속 직원도 함께 체크됩니다. 검색하면 찾은 행의 상위 조직이 함께 남습니다.'));
  separator(ctx);
  button(ctx, h('Expand all', '모두 펼치기'), () => grid.expandAll());
  button(ctx, h('Collapse all', '모두 접기'), () => grid.collapseAll());
  button(ctx, h('Search "team"', '"팀" 검색'), () => grid.setQuickFilter(h('team', '팀')));
  button(ctx, h('Clear search', '검색 지우기'), () => grid.setQuickFilter(''));
  return grid;
}

조직도, 자재 명세서(BOM), 폴더 목록처럼 이미 계층이 있는 데이터는 트리로 보여 줄 수 있습니다. 행마다 getParentId로 부모를 가리키면 그리드가 그 행 아래에 넣고, 펼치고 접는 화살표를 붙입니다. 부모를 찾을 수 있도록 getRowId로 고유 ID를 주어야 합니다. 같은 단계 안의 순서는 데이터 순서나 지금 정렬을 따릅니다.

필터와 빠른 검색을 걸어도 찾은 행의 상위 행이 함께 남으므로, 결과가 트리의 어디에 있는지 항상 보입니다. rowSelection: 'multiple'과 groupSelectsChildren: true를 주면 부서를 체크할 때 소속 직원이 모두 함께 체크됩니다. 화살표를 누르거나, 첫 컬럼에서 오른쪽·왼쪽 방향키로 펼치고 접습니다. 스크린리더에는 treegrid로 전달됩니다.

createGrid(el, {
  columns: [{ field: 'name', header: 'Organization' }, { field: 'budget', type: 'number' }],
  data: [
    { id: 'hq', parent: null, name: 'Head office', budget: 1200 },
    { id: 'dev', parent: 'hq', name: 'Development', budget: 640 },
    { id: 'web', parent: 'dev', name: 'Web team', budget: 260 },
  ],
  getRowId: r => r.id,                       // required: parents are found by id
  treeData: { getParentId: r => r.parent },  // null or undefined = top level
  groupDefaultExpanded: 1,                   // 0 = collapsed, -1 = everything open
  rowSelection: 'multiple',
  groupSelectsChildren: true,                // checking a parent checks its children
});

grid.expandAll();
grid.collapseAll();
grid.setGroupExpanded('dev', true);          // a tree row's key is its id
grid.on('groupToggle', e => console.log(e.key, e.expanded));

서버에서 자식 불러오기

자식 행이 서버에 있다면 자식이 있는 행을 hasChildren으로 알려 주고, 처음 펼칠 때 실행되는 loadChildren에서 불러오세요. 불러오기 전에도 화살표가 보이며, 불러온 자식은 그 행의 ID를 부모 ID로 가져야 합니다.

// folders whose children live on the server: loaded on first expand
createGrid(el, {
  columns, data: roots, getRowId: r => r.id,
  treeData: {
    getParentId: r => r.parent,
    hasChildren: r => r.folder,             // shows the arrow before anything is loaded
    loadChildren: r => fetch(`/api/files?parent=${r.id}`).then(res => res.json()),
  },
});
grid.on('childrenLoadFailed', e => console.error(e.row.id, e.error));

행을 끌어서 다른 부모 아래로 옮기게 하려면 행 드래그를 보세요.

옵션, 메서드, 이벤트

이름타입설명
treeData.getParentId(row)unknown부모의 ID. 최상위 행이면 null이나 undefined. getRowId가 필요합니다.
treeData.setParentId(row, parentId, parent)void행에 새 부모를 저장합니다. 행을 다른 부모로 끌어 옮길 때 필요합니다(행 드래그 참고).
treeData.hasChildren / loadChildren(row) => boolean / (row) => Promise<Row[]> | Row[]자식이 아직 없는 행과, 처음 펼칠 때 자식을 불러오는 함수. 불러온 자식은 그 행의 ID를 부모 ID로 가져야 합니다.
groupDefaultExpandednumber처음에 펼칠 단계 수: 0 없음(기본), n단계, -1 전부.
groupSelectsChildrenboolean부모를 체크하면 자식도 모두 함께 체크(또는 해제)됩니다.
expandAll() / collapseAll() / setGroupExpanded(id, open)void트리 행을 펼치거나 접습니다. 트리 행의 키는 행 ID입니다.
groupToggle / childrenLoaded / childrenLoadFailedevents행이 펼쳐지거나 접혔고, loadChildren이 끝났거나 실패했습니다.

이 페이지에 대한 질문

계층 데이터를 트리로 보여 주려면?

getRowId로 행마다 ID를 주고 treeData: { getParentId: row => row.parent }를 설정하세요. hasChildren과 loadChildren을 주면 처음 펼칠 때 서버에서 자식을 불러옵니다.