Event handlers
Lifecycle hooks for custom logic during import
Event handlers let you hook into the import lifecycle to add custom validation, transformation, or handle submission.
onBeforeRowsChange
Fired after validation and transformation, and whenever a cell value changes.
Type signature:
onBeforeRowsChange?: (
changedTableRows: ITableRows,
range: ITableRowRange,
fullTableRows: ITableRowsInternal
) => Promise<{ changedRows: ITableRows }>Parameters:
| Parameter | Type | Description |
|---|---|---|
changedTableRows | ITableRows | Rows that changed (on initial load, all rows) |
range | ITableRowRange | Range of changed rows { start: number, end: number } |
fullTableRows | ITableRowsInternal | Complete table data (internal format) |
Returns: Promise with { changedRows: ITableRows }
Use built-in features first
Before using this event, check if your use case can be solved with rules validators or data sources.
These built-in solutions are significantly faster because they run in web workers with parallel processing and don't block the main thread.
Only use onBeforeRowsChange when:
- You need to validate against a remote API (not yet supported natively)
- Your logic is truly impossible to express with rules or data sources
- You need to perform complex async operations
Example: Remote API validation
This is a valid use case since remote validation isn't supported natively (yet).
eventHandlers: {
onBeforeRowsChange: async (changedRows) => {
for (const row of changedRows) {
const email = row.email.currentValue as string;
// Check if email exists in your system via API
if (email) {
const response = await fetch(`/api/check-email?email=${email}`);
const { exists } = await response.json();
if (exists) {
row.email.newError = {
type: 'custom',
severity: 'e',
message: 'This email is already registered'
};
}
}
}
return { changedRows };
}
}Performance warning
This event runs on the main thread and can significantly slow down the import for large datasets. Each cell change triggers this function, so:
- Avoid heavy computations
- Minimize API calls (consider debouncing or batching)
- Keep logic as simple as possible
For most validation and transformation needs, use the built-in validators, transformers, and data sources instead.
onSubmit
Fired when the user clicks submit. Receive the final validated data and send it to your backend.
Type signature:
onSubmit?: (
tableRows: ITableRowsInternal,
meta: IMeta,
cellErrors: ICellErrorWithMeta[],
submitMeta: CreateImportResponse | null
) => Promise<void>Parameters:
| Parameter | Type | Description |
|---|---|---|
tableRows | ITableRowsInternal | Final validated table data |
meta | IMeta | Import metadata (file info, row count, error count, etc.) |
cellErrors | ICellErrorWithMeta[] | Unresolved errors at submission time |
submitMeta | CreateImportResponse | null | Ivandt server response (if using hosted mode) |
Example:
eventHandlers: {
onSubmit: async (tableRows, meta, cellErrors, submitMeta) => {
// Send data to your backend
const response = await fetch('/api/import', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
data: tableRows,
fileName: meta.file.name,
rowCount: meta.rowCount,
errorCount: cellErrors.length
})
});
if (!response.ok) {
throw new Error('Import failed');
}
console.log('Import successful!');
}
}onSubmitError
Fired if an unexpected error occurs during submission.
Type signature:
onSubmitError?: (error: any) => voidParameters:
| Parameter | Type | Description |
|---|---|---|
error | any | The error that occurred |
Example:
eventHandlers: {
onSubmitError: (error) => {
console.error('Submission failed:', error);
alert('Failed to submit data. Please try again.');
}
}onSubmitCancel
Fired when the user cancels submission (only when allowSubmitCancel is enabled).
Type signature:
onSubmitCancel?: () => voidExample:
eventHandlers: {
onSubmitCancel: () => {
console.log('User cancelled submission');
// Clean up or redirect
}
}onFileUpload
Fired immediately after the user selects a file. Use this to upload the file to your server for processing or storage.
Type signature:
onFileUpload?: (file: File, fileMeta: IFileInfo) => voidParameters:
| Parameter | Type | Description |
|---|---|---|
file | File | The uploaded file object |
fileMeta | IFileInfo | File metadata (name, size, type, etc.) |
Example:
eventHandlers: {
onFileUpload: async (file, fileMeta) => {
const formData = new FormData();
formData.append('file', file);
await fetch('/api/upload', {
method: 'POST',
body: formData
});
console.log(`Uploaded ${fileMeta.name} (${fileMeta.size} bytes)`);
}
}