FreeGridv1.15.1한국어

valueFormatter and valueParser

valueFormatter turns a value into the text shown on screen, in search, tooltips, copy and exports; valueParser turns typed or pasted text back into a value.

Live demoFormatter and parser

Prices with their row's currency; type "$ 1,200" back.

Code for this demo
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 covers the usual number and date patterns. When the text depends on your own rules or on other fields of the row — a currency from the row, a code shown as a label, a size in KB or MB — give the column a valueFormatter. It returns the text; the value in the row stays as it is.

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') },
]
NameTypeDescription
valueunknownThe cell value (after valueGetter or the nested field).
formattedstringWhat `format` and the locale would show; useful to add to it.
rowRow | undefinedThe row; absent where text is made without one (the set filter list, group and summary values).
columnColumnDefThe column definition.

Where the text is used

PlaceUses valueFormatter
Cells, tooltips, auto-sizeyes
Quick search, find (Ctrl+F)yes: "paused" finds P
Copy (Ctrl+C), CSV, print, PDFyes
ExcelText cells use it; number and date cells stay numbers and dates so Excel can add them up
Group rows and the summarySums and averages of the same type use it (without a row); counts and shares do not
Sorting and column filtersNo: they compare the values, so 1,200 KRW sorts as 1200

valueParser: text back to a value

Once a cell shows "1,200 KRW", people type and paste text like that. valueParser turns it into the value to store. It runs for the text editor, paste, fill from text and file import. Return undefined to refuse the text: the editor stays open with the "invalid value" message, and a paste skips the cell. The column rules (required, validate, min/max) still run on the result.

{
  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;
  },
}
NameTypeDescription
textstringWhat was typed or pasted.
rowRowThe row being edited (a new, empty row for lines that paste adds).
oldValueunknownThe value before.
columnColumnDefThe column definition.

Copy and paste back

With a valueFormatter, Ctrl+C copies the text the cell shows. Give the same column a valueParser so that pasting it back, here or in another grid, gives the value again. Without a valueFormatter the clipboard keeps raw numbers and ISO dates, as before.

Editors with their own list (select, combo, radio, multiSelect) already show option labels and read them back; valueParser, when given, takes over the pasted text for them too. A valueFormatter that throws is reported once in the console and the plain text is shown.

Questions about this page

How do I show a code as a label, like A as Active, without changing the data?

Give the column valueFormatter: p => LABELS[p.value]. The cell, quick search, find, the tooltip, CSV and copy use the label; the row keeps 'A'. For a fixed list you can also use a select editor, whose option labels are shown the same way.

Why use valueFormatter instead of a renderer?

A renderer only draws the cell. valueFormatter gives text, so the same text is searched, found, copied, exported and measured for auto-size, and it keeps working with grouping and the summary.