FreeGridv1.15.1English

중첩 필드(address.city)

field: 'address.city'로 중첩 객체를 읽고 씁니다. 표시·정렬·필터·편집·붙여넣기·실행 취소·변경 추적·내보내기가 모두 경로를 따릅니다.

실행 예제중첩 필드

address.city를 고치고 행 객체가 바뀌는 것 보기.

이 데모의 코드
import { createGrid, type Row } from '@freegridjs/core';
import { makeRows } from '../data';
import { button, separator, text, tr, type DemoContext } from '../ui';

const CITIES = ['Seoul', 'Busan', 'Incheon', 'Daegu', 'Tokyo', 'Paris'];

export default function mount(ctx: DemoContext) {
  const h = (en: string, ko: string) => tr(ctx.lang, { en, ko });
  // nested rows, as an API sends them; every fifth customer has no address yet
  const data: Row[] = makeRows(300).map((r, i) => ({
    id: r.id,
    customer: { name: r.name, company: r.company, ...(i % 5 ? { address: { city: CITIES[i % CITIES.length], zip: String(10000 + i * 37).slice(0, 5) } } : {}) },
    total: r.q1,
  }));
  const grid = createGrid(ctx.host, {
    columns: [
      { field: 'id', header: 'ID', type: 'number', width: 70 },
      { field: 'customer.name', header: h('Customer', '고객'), width: 160 },
      { field: 'customer.company', header: h('Company', '회사'), width: 150 },
      { field: 'customer.address.city', header: h('City', '도시'), width: 120, editable: true, editor: { type: 'combo', options: CITIES } },
      { field: 'customer.address.zip', header: h('ZIP', '우편번호'), width: 100, editable: true },
      { field: 'total', header: h('Total', '합계'), type: 'number', format: '#,##0', width: 110 },
    ],
    data, locale: ctx.lang, getRowId: r => String(r.id), filterRow: true,
  });
  grid.on('cellValueChanged', e => ctx.log(`#${e.row.id} ${e.colId}: ${String(e.oldValue ?? '')} → ${String(e.newValue)}  ·  customer = ${JSON.stringify(e.row.customer)}`));
  text(ctx, h('Edit a city or ZIP: the log shows the nested object. Rows without an address get one. Sort, filter and Ctrl+Z work as usual.',
    '도시나 우편번호를 고쳐 보세요. 로그에 중첩 객체가 보입니다. 주소가 없던 행에는 주소가 생깁니다. 정렬, 필터, Ctrl+Z도 그대로 됩니다.'));
  separator(ctx);
  button(ctx, h('Changes', '변경 내역'), () => ctx.log(JSON.stringify(grid.getChanges().map(c => ({ id: c.row.id, colId: c.colId, old: c.oldValue, new: c.newValue })))));
  button(ctx, h('Revert all', '모두 되돌리기'), () => grid.revertChanges());
  return grid;
}

API에서 오는 데이터는 자주 중첩되어 있습니다. 주문에 customer 객체가 있고 그 안에 address가 있는 식입니다. 값까지의 경로를 키 사이에 점을 찍어 컬럼의 field로 쓰면, 그리드가 그 위치에서 읽고 씁니다. 행을 미리 펼치거나 valueGetter를 쓸 필요가 없습니다.

const rows = [
  { id: 1, customer: { name: 'Kim', address: { city: 'Seoul', zip: '04524' } }, total: 1200 },
  { id: 2, customer: { name: 'Lee', address: { city: 'Busan' } }, total: 800 },
  { id: 3, customer: { name: 'Park' }, total: 450 },          // no address yet
];

createGrid(el, {
  getRowId: row => String(row.id),
  columns: [
    { field: 'customer.name', header: 'Customer' },
    { field: 'customer.address.city', header: 'City', editable: true },
    { field: 'customer.address.zip', header: 'ZIP', editable: true },
    { field: 'total', type: 'number' },
  ],
  data: rows,
});

경로를 따르는 기능

기능중첩 필드일 때
표시, 정렬, 필터, 빠른 검색, 찾기경로의 값을 읽음. 중간 객체가 없으면 빈 값
편집, 붙여넣기, 채우기, Delete중첩 객체에 씀. 중간 객체가 없으면 만들어짐(위 3행에 customer.address가 생김)
실행 취소, revertChanges이전 값을 되돌림. revertChanges는 편집이 만든 객체도 지움
변경 추적getChanges()가 경로 컬럼과 이전·새 값을 돌려줌. 원본은 중첩 객체를 따로 복사해 두어 이후 편집에 바뀌지 않음
applyTransaction(실시간 데이터){ id, customer: { … } } 업데이트는 객체를 바꾸고, 중첩 컬럼이 다시 그려지며 깜빡이고 다시 정렬됨
CSV, 엑셀, PDF, 인쇄, 가져오기경로의 값을 내보냄. 가져온 파일은 중첩 객체를 채움
컬럼 id, 상태, 필터id를 주지 않으면 경로('customer.address.city')가 id

점이 들어간 키

행에 경로 전체가 하나의 키로 있으면({ 'customer.name': 'Kim' }, 일부 내보내기 결과처럼) 그 키가 우선이며 평평한 키 하나로 읽고 씁니다. 이미 평평한 데이터도 그대로 동작합니다.

중첩 필드와 valueGetter

field: 'a.b'valueGetter
읽기예예
편집, 붙여넣기, 채우기예아니요
여러 필드로 계산아니요예 (row => row.qty * row.price)
배열(items[0].name)'items.0.name'이 첫 항목을 읽음예

TypeScript에서

행에 타입을 주면 편집기가 경로를 자동완성하고 검사합니다. ColumnDef<Order>는 customer.address.city를 받고 오타는 거부합니다. TypeScript를 보세요.

경로는 일반 객체와 배열(items.0.qty)을 따라갑니다. 끝에 있는 Date나 클래스 인스턴스는 값 자체입니다. 변경 추적과 실행 취소는 일반 객체와 배열만 따로 복사해 둡니다. 클래스 인스턴스는 그대로 공유하므로 그 안을 고친 것(클래스 객체에 field: 'owner.name')은 변경으로 잡히지 않습니다. 편집하는 값은 일반 객체로 두세요.

이 페이지에 대한 질문

address.city 같은 중첩 속성을 컬럼에 보여 주려면?

경로를 field에 쓰면 됩니다: { field: 'address.city' }. 다른 필드처럼 읽고 정렬·필터·편집하며, 편집하면 row.address.city에 다시 씁니다.

중첩 데이터에 아직 valueGetter가 필요한가요?

단순한 경로라면 필요 없습니다. valueGetter는 읽기만 해서 편집할 수 없지만, 점이 들어간 field는 편집됩니다. 여러 필드로 계산하는 값에만 valueGetter를 쓰세요.