FreeReportv0.9.0English

이벤트

뷰어와 디자이너 이벤트 예제: onReady, onParamsSubmit, onPageChange, onError, onOutput, fetchData, onChange, onSave를 언제 어떻게 쓰는지 설명합니다.

이벤트로 뷰어와 디자이너의 동작에 맞춰 페이지가 반응하게 합니다. 옵션에 함수로 넘기며 모두 선택 사항입니다. 사용자가 보고서를 조회할 때 일어나는 순서대로 정리했습니다.

이벤트어디언제
onParamsSubmit(params)viewer사용자가 조회를 누름. false면 머물고, 바꾼 조건을 돌려주면 그 값으로 조회. setParams()에는 불리지 않습니다.
fetchData(params)viewer행 불러오기: 처음, 조회, setParams() 때. { rows }(또는 Promise)를 돌려줍니다.
onReady({ pages, rows, ms, params })viewer보고서를 다 만들어 보여 줌(실행할 때마다).
onPageChange(page, total)viewer보고 있는 페이지가 바뀜.
onOutput(e)viewer · createReport인쇄·파일 저장 직전(print, pdf, xlsx, xlsx-data, csv, hwpx). false면 취소.
onError(error, during)viewer실패: 'data', 'layout', 'output'.
onChange(definition)designer양식이 바뀔 때마다(실행 취소·다시 실행 포함).
onSave(definition)designer저장 버튼이나 Ctrl+S.

뷰어 이벤트

조회 전에 조건을 검사하고, 조회가 끝나면 건수를 보여 주고, 페이지를 따라가고, 오류를 한곳에서 처리하고, 모든 출력을 기록하는 예입니다.

const viewer = createViewer(el, {
  definition,
  params: { from: '2026-10-01', to: '2026-10-31', dept: '' },

  // 1. the user pressed 조회/Run: check or adjust the parameters first
  onParamsSubmit: params => {
    if (String(params.from) > String(params.to)) {
      alert('시작일이 종료일보다 늦습니다.');
      return false;                                   // stay on the panel, nothing is loaded
    }
    return { ...params, dept: params.dept || myDept };  // or return changed parameters
  },

  // 2. load the rows for those parameters (start, 조회, setParams)
  fetchData: params => fetch('/api/sales?' + new URLSearchParams(params as Record<string, string>)).then(r => r.json()),

  // 3. after every successful run
  onReady: ({ pages, rows, ms, params }) => {
    summary.textContent = pages + '쪽 · ' + rows.toLocaleString() + '건 (' + ms + 'ms)';
    printBtn.disabled = rows === 0;
  },

  // 4. the page in view changed (scroll, buttons, keyboard, goTo)
  onPageChange: (page, total) => { pager.textContent = page + ' / ' + total; },

  // 5. loading, layout, printing or saving failed (the viewer also shows a message)
  onError: (error, during) => {
    if (during === 'data' && /401/.test(error.message)) location.href = '/login';
    else reportError(error);                           // your error tracker
  },

  // 6. before every print and file: log it, ask for a reason, or return false to block it
  onOutput: async e => {
    const reason = e.kind === 'print' ? prompt('출력 사유를 입력하세요') : '';
    if (reason === null) return false;
    await fetch('/api/report-logs', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ ...e, reason }) });
  },
});
  • onParamsSubmit은 사용자가 조회를 누를 때만 불립니다. 코드에서 viewer.setParams()를 부르면 바로 fetchData로 갑니다.
  • onReady는 처음 불러올 때와 조회, setData, setParams, setDefinition 뒤마다 불리므로 뷰어 바깥의 건수·버튼을 갱신하기 좋은 곳입니다.
  • 이벤트 함수에서 오류가 나도 콘솔에만 남고 뷰어는 계속 동작합니다.

디자이너 이벤트

편집하는 동안 임시 저장하고, 서버에 저장하고, 저장하지 않고 떠날 때 경고하는 예입니다.

let dirty = false;
const designer = createDesigner(el, {
  definition, data: { rows: sample },
  // every change (move, resize, property, undo/redo): keep a draft, mark the page as changed
  onChange: def => {
    dirty = true;
    localStorage.setItem('draft:sales', JSON.stringify(def));
  },
  // Ctrl+S or the Save button
  onSave: async def => {
    const res = await fetch('/api/reports/sales', { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify(def) });
    if (res.ok) { dirty = false; localStorage.removeItem('draft:sales'); }
  },
});
addEventListener('beforeunload', e => { if (dirty) e.preventDefault(); });   // unsaved changes warning

React, Vue, Svelte, Angular에서

// React
<FreeReportViewer definition={def} fetchData={load} onReady={e => setCount(e.rows)} onPageChange={setPage} onError={showError} />

<!-- Vue -->
<FreeReportViewer :definition="def" :fetch-data="load" :on-ready="e => (count = e.rows)" :on-page-change="p => (page = p)" />

<!-- Svelte 5: onReady gives the viewer itself; the core onReady is onRendered -->
<FreeReportViewer {definition} fetchData={load} onRendered={e => (count = e.rows)} onPageChange={p => (page = p)} />

<!-- Angular: outputs -->
<free-report-viewer [definition]="def" [fetchData]="load" (rendered)="count = $event.rows" (pageChange)="page = $event.page" (error)="show($event.error)" />

출력 이벤트(onOutput)로 출력 이력을 남기는 예는 따로 정리했습니다. 출력 이력