Ivandt logo

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:

ParameterTypeDescription
changedTableRowsITableRowsRows that changed (on initial load, all rows)
rangeITableRowRangeRange of changed rows { start: number, end: number }
fullTableRowsITableRowsInternalComplete 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:

ParameterTypeDescription
tableRowsITableRowsInternalFinal validated table data
metaIMetaImport metadata (file info, row count, error count, etc.)
cellErrorsICellErrorWithMeta[]Unresolved errors at submission time
submitMetaCreateImportResponse | nullIvandt 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) => void

Parameters:

ParameterTypeDescription
erroranyThe 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?: () => void

Example:

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) => void

Parameters:

ParameterTypeDescription
fileFileThe uploaded file object
fileMetaIFileInfoFile 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)`);
  }
}