플러그인 설명 / 트리개발 매뉴얼로 돌아가기

트리 플러그인

트리 · treePlugin

부모 키를 가진 평탄한 행 배열을 계층으로 표시합니다. 5단계 예제에서 연결선·초기 펼침·접기·말단 검색 시 조상 유지를 확인합니다.

설치 함수: treePlugin(config) · 해제 이름: tree

설정 속성 · 기본값

필수값은 해당 입력에서 반드시 제공하는 값입니다. 조건부 필수값은 설명에 적힌 기능을 사용할 때 필요합니다. 표시가 없는 옵션은 생략할 수 있으며 기본값을 사용합니다. 빈 문자열·누락과 0·false를 혼동하지 마세요.

설정 위치와 동작
설정기본값설명
field첫 컬럼트리 들여쓰기와 펼침 버튼을 표시할 컬럼 field입니다.
parentFieldparentId각 행의 부모 rowKey가 들어 있는 데이터 필드입니다. 루트는 null 또는 부모 없음입니다.
showLinesfalse들여쓰기 영역에 계층 연결선을 표시합니다.
defaultExpandedfalsetrue는 이미 적재된 부모를 처음 펼치고 false는 접습니다. 이후 사용자가 접은 상태를 유지합니다.
expanded생략처음 펼칠 행 키 배열. 지정하면 defaultExpanded보다 우선합니다. []는 처음 모두 접힘입니다.
hasChildrenFieldhasChildren자식이 아직 적재되지 않았더라도 이 필드가 true이면 펼침 버튼을 표시합니다.
loadChildren없음loadChildren(row,{signal})이 부모 키를 포함하는 자식 행 배열을 반환합니다. 처음 수동으로 펼칠 때 조회합니다.

사용 순서

  1. 모든 행에 고유 rowKey를 넣고 부모 행 키를 parentField에 지정합니다.
  2. treePlugin(config) 또는 plugins:[treePlugin()]과 options.tree로 구성합니다. 같은 속성은 플러그인 config가 우선합니다.
  3. 초기 상태는 defaultExpanded 또는 expanded로 정합니다. lazy 행은 hasChildrenField와 loadChildren을 함께 구성합니다.

연결 API

플러그인 또는 연결된 Core API
호출동작
grid.toggleTree(id)해당 행의 펼침 상태를 전환합니다. lazy 조회를 포함하며 Promise를 반환합니다.

필수값 grid.toggleTree 인수: id

grid.setTreeLines(boolean)연결선을 켜거나 끄고 다시 표시합니다.

필수값 grid.setTreeLines 인수: boolean

설치 · 해제 · Vue 3 수명주기

생성 시 plugins에 등록하거나, 아직 설치하지 않은 인스턴스에서 grid.install을 호출합니다. 같은 name은 중복 설치할 수 없습니다. 설정에 쓰는 데이터·함수는 아래 전체 예제 소스를 참고하세요.

grid.install(treePlugin({ field: 'name', showLines: true, defaultExpanded: true }));
grid.uninstall('tree'); // 플러그인 해제
// Vue 3 컴포넌트가 종료될 때
onBeforeUnmount(() => grid.destroy());

미완료 자식 조회를 취소하고 트리 변환·셀 렌더러를 제거합니다. role을 grid로 복원하고 설치 전의 toggleTree/setTreeLines를 복원합니다.

관련 이벤트

  • render
  • error
  • datachange

이벤트 구독은 grid.on(name, (detail, grid) => {})를 사용합니다. 해제 함수 또는 grid.off로 구독을 정리하세요.

실행 예제 · 실제 원본

아래 소스는 examples/features/tree.js와 Vue 원본입니다. 해당 예제 경로를 기준으로 import하며, 행 데이터는 별도 파일을 함께 사용합니다.

JavaScript 전체 소스 · tree.js
import { ZixoGrid, treePlugin } from '../../src/index.js';
import { rows } from './tree.data.js';
import { createToolbar } from '../feature-controls.js';
const host = document.querySelector('#grid'),
  toolbar = document.querySelector('#toolbar'),
  report = document.querySelector('#report');
const { button, select } = createToolbar(toolbar, report);
const options = {
  rowKey: 'id',
  height: 360,
  rows: rows,
  columns: [{ field: 'name', title: '업무', width: 360 }],
  plugins: [
    treePlugin({ field: 'name', showLines: true, defaultExpanded: true }),
  ],
};

let grid = new ZixoGrid(host, options);

window.addEventListener('pagehide', () => grid.destroy(), { once: true });
grid.on(
  'validationerror',
  (detail) => (report.textContent = detail.error.message),
);
select('처음 표시', ['펼침', '접힘'], (value) => {
  grid.destroy();
  grid = new ZixoGrid(host, {
    ...options,
    plugins: [
      treePlugin({
        field: 'name',
        showLines: true,
        defaultExpanded: value === '펼침',
      }),
    ],
  });
});
button('연결선 켜기', () => grid.setTreeLines(true));
button('연결선 끄기', () => grid.setTreeLines(false));
button('5단계 검색', () => grid.setSearch('5단계'));
button('검색 해제', () => grid.setSearch(''));
report.textContent =
  '100행을 5단계 계층으로 구성합니다. defaultExpanded: true는 처음 펼침, false는 처음 접힘이며 기본값은 false입니다. 5단계 검색 시 1~4단계 조상을 유지합니다. parentId로 부모 행의 키를 참조합니다.';
Vue 3 전체 소스 · vue-tree.vue
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { ZixoGrid, treePlugin } from '../../src/index.js';
import { rows } from './tree.data.js';

// Instance and DOM belong to this component, never to window or a global ID.
const gridHost = ref(null);
const message = ref('');
const controls = ref([]);

let grid;
let alive = true;

async function run(action, value) {
  try {
    const result = await action(value);
    if (alive && result !== undefined)
      message.value =
        typeof result === 'string' ? result : JSON.stringify(result, null, 2);
  } catch (error) {
    if (alive) message.value = error.message;
  }
}

const button = (label, action) =>
  controls.value.push({ kind: 'button', label, action });
const select = (label, values, action) =>
  controls.value.push({
    kind: 'select',
    label,
    values,
    value: values[0],
    action,
  });

onMounted(() => {
  const options = {
    rowKey: 'id',
    height: 360,
    rows: rows,
    columns: [{ field: 'name', title: '업무', width: 360 }],
    plugins: [
      treePlugin({ field: 'name', showLines: true, defaultExpanded: true }),
    ],
  };

  grid = new ZixoGrid(gridHost.value, options);

  grid.on(
    'validationerror',
    (detail) => (message.value = detail.error.message),
  );
  select('처음 표시', ['펼침', '접힘'], (value) => {
    grid.destroy();
    grid = new ZixoGrid(gridHost.value, {
      ...options,
      plugins: [
        treePlugin({
          field: 'name',
          showLines: true,
          defaultExpanded: value === '펼침',
        }),
      ],
    });
  });
  button('연결선 켜기', () => grid.setTreeLines(true));
  button('연결선 끄기', () => grid.setTreeLines(false));
  button('5단계 검색', () => grid.setSearch('5단계'));
  button('검색 해제', () => grid.setSearch(''));
  message.value =
    '100행을 5단계 계층으로 구성합니다. defaultExpanded: true는 처음 펼침, false는 처음 접힘이며 기본값은 false입니다. 5단계 검색 시 1~4단계 조상을 유지합니다. parentId로 부모 행의 키를 참조합니다.';
});
onBeforeUnmount(() => {
  alive = false;
  grid?.destroy(); // Cancels grid requests, removes events and releases plugins.
  grid = undefined;
});
defineExpose({ getGrid: () => grid });
</script>

<template>
  <main>
    <h1>트리 · 연결선 · 조상 필터</h1>
    <div class="toolbar">
      <template v-for="(control, index) in controls" :key="index">
        <button
          v-if="control.kind === 'button'"
          type="button"
          @click="run(control.action)"
        >
          {{ control.label }}
        </button>
        <label v-else
          >{{ control.label }}
          <select
            v-model="control.value"
            :aria-label="control.label"
            @change="run(control.action, control.value)"
          >
            <option v-for="value in control.values" :key="value" :value="value">
              {{ value }}
            </option>
          </select>
        </label>
      </template>
    </div>
    <div ref="gridHost" class="vue-grid-host"></div>
    <div class="notes result" aria-live="polite">{{ message }}</div>
  </main>
</template>

제약 사항 · 주의할 동작

  • tree와 grouping은 같은 인스턴스에 함께 설치할 수 없습니다.
  • 미조회 lazy 자식은 defaultExpanded:true만으로 자동 조회하지 않습니다.
  • 여러 lazy 요청이 공유 로딩·오류·재시도 상태를 사용하므로 동시 요청 상태 표시에 제한이 있습니다.
  • 순환 부모 참조는 허용되지 않습니다. 검색에 맞는 행의 조상을 유지하되 사용자가 접은 상태는 유지합니다.

연결 기능 메뉴

트리 · 연결선 · 조상 필터 · Tree / Detail lazy 요청 · 안정적인 행 ID

이 플러그인 상세 페이지 독립 열기 ↗ · 플러그인 설명 전체