값 표시와 입력 해석(valueFormatter, valueParser)
valueFormatter는 값을 화면·검색·툴팁·복사·내보내기에 쓰는 글자로 바꾸고, valueParser는 입력하거나 붙여넣은 글자를 다시 값으로 바꿉니다.
실행 예제값 표시와 입력 해석
행의 통화를 붙인 가격, "$ 1,200"으로 다시 입력.
이 데모의 코드
import { createGrid } from '@freegridjs/core';
import { makeRows } from '../data';
import { button, separator, text, tr, type DemoContext } from '../ui';
const CURRENCIES = ['KRW', 'USD', 'JPY', 'EUR'];
export default function mount(ctx: DemoContext) {
const h = (en: string, ko: string) => tr(ctx.lang, { en, ko });
const STATUS: Record<string, string> = { A: h('Active', '진행'), P: h('Paused', '보류'), X: h('Closed', '종료') };
const data = makeRows(300).map((r, i) => ({ id: r.id, name: r.name, price: r.q1 / 10, currency: CURRENCIES[i % 4], code: 'APX'[i % 3], size: (i * 7919) % 5_000_000 }));
const grid = createGrid(ctx.host, {
columns: [
{ field: 'name', header: h('Name', '이름'), width: 160 },
{
field: 'price', header: h('Price', '가격'), type: 'number', format: '#,##0.00', width: 150, editable: true,
// the row's currency after the number
valueFormatter: p => `${p.formatted} ${p.row?.currency ?? ''}`.trim(),
// '$ 1,200', '1200원' → 1200; no digits → refused
valueParser: p => {
const digits = p.text.replace(/[^0-9.-]/g, '');
return /[0-9]/.test(digits) ? Number(digits) : undefined;
},
},
{ field: 'code', header: h('Status (code)', '상태(코드)'), width: 120, valueFormatter: p => STATUS[String(p.value)] ?? String(p.value ?? '') },
{ field: 'size', header: h('File size', '파일 크기'), type: 'number', width: 110, valueFormatter: p => (Number(p.value) >= 1e6 ? `${(Number(p.value) / 1e6).toFixed(1)} MB` : `${Math.round(Number(p.value) / 1e3)} KB`) },
],
data, locale: ctx.lang,
});
grid.on('cellValueChanged', e => ctx.log(`price stored as ${JSON.stringify(e.newValue)}`));
grid.on('validationFailed', e => ctx.log(`refused "${String(e.value ?? '')}"`));
const box = document.createElement('input');
box.type = 'search';
box.placeholder = h('Quick search: paused, usd, mb', '빠른 검색: 보류, usd, mb');
box.addEventListener('input', () => { grid.setQuickFilter(box.value); ctx.log(`"${box.value}" → ${grid.getDisplayedRowCount()} rows`); });
ctx.controls.append(box);
separator(ctx);
button(ctx, 'CSV', () => grid.exportCsv('formatted.csv'));
text(ctx, h('Type "$ 7,500" or "7500원" into a price; copy a price and paste it into another. The rows keep codes and plain numbers; sorting uses them.',
'가격에 "$ 7,500"이나 "7500원"을 입력하거나, 가격을 복사해 다른 칸에 붙여넣어 보세요. 행에는 코드와 숫자가 그대로 있고 정렬은 그 값을 씁니다.'));
return grid;
}format은 흔한 숫자·날짜 패턴을 다룹니다. 글자가 직접 정한 규칙이나 행의 다른 필드에 따라 달라질 때(행의 통화, 이름으로 보일 코드, KB·MB 단위 크기) 컬럼에 valueFormatter를 주세요. 함수가 글자를 돌려주고, 행의 값은 그대로 남습니다.
const STATUS = { A: 'Active', P: 'Paused', X: 'Closed' };
columns: [
{ field: 'status', valueFormatter: p => STATUS[p.value] ?? String(p.value ?? '') },
{
field: 'price', type: 'number', format: '#,##0.00',
// formatted is what format would show; the row gives the currency
valueFormatter: p => `${p.formatted} ${p.row?.currency ?? ''}`,
},
{ field: 'size', type: 'number', valueFormatter: p => (p.value >= 1e6 ? (p.value / 1e6).toFixed(1) + ' MB' : Math.round(p.value / 1e3) + ' KB') },
]| 이름 | 타입 | 설명 |
|---|---|---|
value | unknown | 셀 값(valueGetter나 중첩 필드를 거친 값). |
formatted | string | `format`과 로케일이 보여 줄 글자. 여기에 덧붙이기 좋습니다. |
row | Row | undefined | 행. 행 없이 글자를 만드는 곳(값 목록 필터, 그룹·합계 값)에서는 없습니다. |
column | ColumnDef | 컬럼 정의. |
글자가 쓰이는 곳
| 위치 | valueFormatter 사용 |
|---|---|
| 셀, 툴팁, 자동 너비 | 예 |
| 빠른 검색, 찾기(Ctrl+F) | 예: "paused"로 P를 찾음 |
| 복사(Ctrl+C), CSV, 인쇄, PDF | 예 |
| 엑셀 | 텍스트 셀은 사용. 숫자·날짜 셀은 엑셀이 계산할 수 있게 숫자·날짜로 남음 |
| 그룹 행과 합계 | 같은 타입의 합계·평균은 사용(행 없이). 개수와 비율은 사용 안 함 |
| 정렬과 컬럼 필터 | 아니요: 값을 비교하므로 1,200 KRW는 1200으로 정렬 |
valueParser: 글자를 다시 값으로
셀에 "1,200 KRW"가 보이면 사람들은 그런 글자를 입력하고 붙여넣습니다. valueParser는 그 글자를 저장할 값으로 바꿉니다. 텍스트 편집기, 붙여넣기, 글자 채우기, 파일 가져오기에 쓰입니다. undefined를 돌려주면 그 글자를 거부합니다. 편집기는 "잘못된 값" 안내와 함께 열려 있고, 붙여넣기는 그 칸을 건너뜁니다. 결과에는 컬럼 규칙(required, validate, min/max)이 그대로 적용됩니다.
{
field: 'price', type: 'number', editable: true,
valueFormatter: p => `${p.formatted} ${p.row?.currency ?? ''}`,
// '$ 7,500', '7500원', '7,500 USD' → 7500; text without digits is refused
valueParser: p => {
const digits = p.text.replace(/[^0-9.-]/g, '');
return /[0-9]/.test(digits) ? Number(digits) : undefined;
},
}| 이름 | 타입 | 설명 |
|---|---|---|
text | string | 입력하거나 붙여넣은 글자. |
row | Row | 편집 중인 행(붙여넣기로 추가되는 줄은 새 빈 행). |
oldValue | unknown | 이전 값. |
column | ColumnDef | 컬럼 정의. |
복사하고 다시 붙여넣기
valueFormatter가 있으면 Ctrl+C는 셀에 보이는 글자를 복사합니다. 같은 컬럼에 valueParser를 주면, 이 그리드나 다른 그리드에 다시 붙여넣었을 때 값으로 돌아옵니다. valueFormatter가 없으면 클립보드에는 예전처럼 숫자 원값과 ISO 날짜가 들어갑니다.
자체 목록이 있는 편집기(select, combo, radio, multiSelect)는 이미 옵션 이름을 보여 주고 다시 읽습니다. valueParser를 주면 붙여넣은 글자도 그 함수가 처리합니다. valueFormatter에서 오류가 나면 콘솔에 한 번 알리고 기본 글자를 보여 줍니다.
이 페이지에 대한 질문
데이터는 그대로 두고 코드 A를 "진행" 같은 이름으로 보여 주려면?
컬럼에 valueFormatter: p => LABELS[p.value]를 주세요. 셀, 빠른 검색, 찾기, 툴팁, CSV, 복사에 이름이 쓰이고 행에는 'A'가 남습니다. 목록이 정해져 있다면 select 편집기를 써도 옵션 이름이 같은 방식으로 보입니다.
renderer 대신 valueFormatter를 쓰는 이유는?
renderer는 셀을 그리기만 합니다. valueFormatter는 글자를 돌려주므로 같은 글자로 검색·찾기·복사·내보내기·자동 너비 계산이 되고, 그룹과 합계에서도 그대로 동작합니다.