> ## Documentation Index
> Fetch the complete documentation index at: https://docs.joyfill.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Event Handling

This document provides comprehensive information about all available events in JoyDoc and how to handle them.

## Event Overview Table

| Event Name          | Event Triggers                                                                                                 | Purpose                                                              |
| ------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `onFocus`           | When a field receives focus                                                                                    | Track field focus events for analytics, validation, or UI updates    |
| `onChange`          | When document data changes (field changes, field position changes, page changes, style changes, theme changes) | Handle document updates, save changes, or sync with external systems |
| `onBlur`            | When a field loses focus                                                                                       | Track field blur events for validation or cleanup operations         |
| `onUploadAsync`     | When images or files are uploaded                                                                              | Handle file uploads to external storage or processing services       |
| `onCaptureAsync`    | When barcode is captured for table barcode cells                                                               | Handle camera capture functionality for barcode fields               |
| `onFileUploadAsync` | When images or files are uploaded                                                                              | Handle field-specific file uploads with custom logic                 |
| `onFileClick`       | When a file in a field is clicked                                                                              | Handle file interactions like opening, previewing, or downloading    |
| `onFileDelete`      | When a file in a field is deleted                                                                              | Handle file deletion with cleanup or confirmation logic              |
| `onError`           | When errors occur (schema validation, license, etc.)                                                           | Handle and display errors to users                                   |

## Event Details

### onFocus

* **Triggered when**: A field receives focus
* **Purpose**: Track field focus events for analytics, validation, or UI updates

**Event signature:**

```jsx theme={null}
onFocus(params, e) => {
  // params contains field and document information
  // e is the native focus event
}

```

**Parameters:**

* `params`: Object containing:
  * `sdk`: 'js'
  * `v`: 1
  * `type`: 'fieldPositionFocus'
  * `_id`: Document ID
  * `identifier`: Document identifier
  * `fileId`: File ID
  * `pageId`: Page ID
  * `fieldId`: Field ID
  * `fieldIdentifier`: Field identifier
  * `fieldPositionId`: Field position ID
  * `fieldRowId`: Row ID (for table fields)
  * `fieldColumnId`: Column ID (for table fields)
  * `fieldColumnIdentifier`: Column identifier (for table fields)
* `e`: Native DOM focus event

**Example:**

```jsx theme={null}
<JoyDoc
  onFocus={(params, e) => {
    console.log('Field focused:', params.fieldId);
    // Call e.blur() to blur the field programmatically
    setTimeout(() => e.blur(), 3000);
  }}
/>

```

### onChange

* **Triggered when**: Document data changes
* **Purpose**: Handle document updates, save changes, or sync with external systems

**Triggered for:**

* **Field changes** - Field value or property updates
* **Field position changes** - Field position, size, or display changes
* **Page changes** - Page creation, updates, or deletion
* **Style changes** - Theme and styling modifications
* **Theme changes** - Toggle between themes

All these will cause changes to the document data

**Event signature:**

```jsx theme={null}
onChange(changelog, doc) => {
  // changelog contains the changes made
  // doc contains the updated document
}

```

**Parameters:**

* `changelog`: Array of change objects describing what was modified
* `doc`: The updated document object

**Example:**

```jsx theme={null}
<JoyDoc
  onChange={(changelog, doc) => {
    console.log('Document changed:', changelog);
    console.log('Updated document:', doc);

    // Save changes to server
    saveDocument(doc);

    // Update local state
    setDocument(doc);
  }}
/>

```

### onBlur

* **Triggered when**: A field loses focus
* **Purpose**: Track field blur events for validation or cleanup operations

**Event signature:**

```jsx theme={null}
onBlur(params, e) => {
  // params contains field and document information
  // e is the native blur event
}

```

**Parameters:**

* `params`: Object containing:
  * `sdk`: 'js'
  * `v`: 1
  * `target`: 'fieldPositionBlur'
  * `_id`: Document ID
  * `identifier`: Document identifier
  * `fileId`: File ID
  * `pageId`: Page ID
  * `fieldId`: Field ID
  * `fieldIdentifier`: Field identifier
  * `fieldPositionId`: Field position ID
  * `fieldRowId`: Row ID (for table fields)
  * `fieldColumnId`: Column ID (for table fields)
  * `fieldColumnIdentifier`: Column identifier (for table fields)
* `e`: Native DOM blur event

**Example:**

```jsx theme={null}
<JoyDoc
  onBlur={(params, e) => {
    console.log('Field blurred:', params.fieldId);

    // Validate field on blur
    validateField(params.fieldId);
  }}
/>

```

### onUploadAsync

* **Triggered when**: Images or files are uploaded
* **Purpose**: Handle file uploads to external storage or processing services

**Event signature:**

```jsx theme={null}
onUploadAsync(params, fileUploads) => {
  // params contains upload context
  // fileUploads contains the files to upload
  // Must return array of file objects with url, fileName, filePath
}

```

**Parameters:**

* `params`: Object containing upload context and document information
* `fileUploads`: Array of file objects to upload

**Return value:** Array of file objects with:

* `url`: Public URL of uploaded file
* `fileName`: Name of the file
* `filePath`: Path to the file

**Example:**

```jsx theme={null}
<JoyDoc
  onUploadAsync={async (params, fileUploads) => {
    console.log('Uploading files:', fileUploads);

    const uploadPromises = fileUploads.map(async (file) => {
      // Upload to your storage service
      const uploadedFile = await uploadToS3(file);

      return {
        url: uploadedFile.url,
        fileName: uploadedFile.fileName,
        filePath: uploadedFile.filePath
      };
    });

    return await Promise.all(uploadPromises);
  }}
/>

```

### onCaptureAsync

* **Triggered when**: Barcode is captured for table barcode cells
* **Purpose**: Handle camera capture functionality for barcode fields

**Event signature:**

```jsx theme={null}
onCaptureAsync(params) => {
  // params contains capture context
  // Must return URL string of captured barcode
}

```

**Parameters:**

* `params`: Object containing capture context

**Return value:** String data of the captured barcode

**Example:**

```jsx theme={null}
<JoyDoc
  onCaptureAsync={async (params) => {
    console.log('Barcode capture initiated:', params);

    // Open camera and capture barcode
    const barcodeData = await captureBarcode();

    return barcodeData;
  }}
/>

```

### onFileUploadAsync

* **Triggered when**: Images or files are uploaded
* **Purpose**: Handle field-specific file uploads with custom logic

**Event signature:**

```jsx theme={null}
onFileUploadAsync(params, fileUploads) => {
  // params contains field and upload context
  // fileUploads contains the files to upload
  // Must return array of file objects with url, fileName, filePath
}

```

**Parameters:**

* `params`: Object containing field information and upload context
* `fileUploads`: Array of file objects to upload

**Return value:** Array of file objects with:

* `url`: Public URL of uploaded file
* `fileName`: Name of the file
* `filePath`: Path to the file

**Example:**

```jsx theme={null}
// Configure in fieldSettings
const fieldSettings = {
  field: {
    onFileUploadAsync: async (params, fileUploads) => {
      console.log('Field-specific upload:', params.fieldId, fileUploads);

      // Custom upload logic for this specific field
      const uploadPromises = fileUploads.map(async (file) => {
        const uploadedFile = await customUploadService(file, params.fieldId);

        return {
          url: uploadedFile.url,
          fileName: uploadedFile.fileName,
          filePath: uploadedFile.filePath
        };
      });

      return await Promise.all(uploadPromises);
    }
  }
};

<JoyDoc
  fieldSettings={fieldSettings}
/>

```

### onFileClick

* **Triggered when**: A file in a field is clicked
* **Purpose**: Handle file interactions like opening, previewing, or downloading

**Event signature:**

```jsx theme={null}
onFileClick(params, urlObject) => {
  // params contains field and file context
  // urlObject contains file information
}

```

**Parameters:**

* `params`: Object containing:
  * `fileId`: File ID
  * `pageId`: Page ID
  * `fieldId`: Field ID
  * `fieldIdentifier`: Field identifier
  * `fieldPositionId`: Field position ID
* `urlObject`: Object containing:
  * `url`: File URL
  * `fileName`: File name
  * `filePath`: File path

**Example:**

```jsx theme={null}
// Configure in fieldSettings
const fieldSettings = {
  field: {
    onFileClick: (params, urlObject) => {
      console.log('File clicked:', urlObject);

      // Open file in new tab
      window.open(urlObject.url, '_blank');
    }
  }
};

<JoyDoc
  fieldSettings={fieldSettings}
/>

```

### onFileDelete

* **Triggered when**: A file in a field is deleted
* **Purpose**: Handle file deletion with cleanup or confirmation logic

**Event signature:**

```jsx theme={null}
onFileDelete(params, urlObject) => {
  // params contains field and file context
  // urlObject contains file information
}

```

**Parameters:**

* `params`: Object containing:
  * `fileId`: File ID
  * `pageId`: Page ID
  * `fieldId`: Field ID
  * `fieldIdentifier`: Field identifier
  * `fieldPositionId`: Field position ID
* `urlObject`: Object containing:
  * `url`: File URL
  * `fileName`: File name
  * `filePath`: File path

**Example:**

```jsx theme={null}
// Configure in fieldSettings
const fieldSettings = {
  field: {
    onFileDelete: async (params, urlObject) => {
      console.log('File deleted:', urlObject);

      // Show confirmation dialog
      const confirmed = await showConfirmDialog(
        `Are you sure you want to delete ${urlObject.fileName}?`
      );

      if (confirmed) {
        // Delete from storage service
        await deleteFromStorage(urlObject.filePath);
      }

      return confirmed;
    }
  }
};

<JoyDoc
  fieldSettings={fieldSettings}
/>

```

### onError

* **Triggered when**: Errors occur (schema validation, license validation, etc.)
* **Purpose**: Handle and display errors to users

**Event signature:**

```jsx theme={null}
onError(error) => {
  // error contains error information
}

```

**Parameters:**

* `error`: Object containing error information:
  * For schema validation errors: Validation error details
  * For license errors: `{ code: 'LICENSE_VALIDATION_ERROR', message: string, type: 'license' }`

**Example:**

```jsx theme={null}
<JoyDoc
  onError={(error) => {
    console.error('JoyDoc Error:', error);

    if (error.type === 'license') {
      showLicenseError(error.message);
    } else {
      showGenericError('An error occurred. Please try again.');
    }
  }}
/>

```

## Complete Example

Here's a complete example showing how to use all events:

```jsx theme={null}
import React, { useState } from 'react';
import JoyDoc from './JoyDoc';

const MyJoyDocApp = () => {
  const [doc, setDoc] = useState(initialDoc);
  const [isLoading, setIsLoading] = useState(false);

  const fieldSettings = {
    field: {
      onFileUploadAsync: async (params, fileUploads) => {
        setIsLoading(true);
        try {
          const uploadPromises = fileUploads.map(async (file) => {
            const uploadedFile = await uploadToS3(file);
            return {
              url: uploadedFile.url,
              fileName: uploadedFile.fileName,
              filePath: uploadedFile.filePath
            };
          });
          return await Promise.all(uploadPromises);
        } finally {
          setIsLoading(false);
        }
      },
      onFileClick: (params, urlObject) => {
        window.open(urlObject.url, '_blank');
      },
      onFileDelete: async (params, urlObject) => {
        const confirmed = await showConfirmDialog(
          `Delete ${urlObject.fileName}?`
        );
        if (confirmed) {
          await deleteFromStorage(urlObject.filePath);
        }
        return confirmed;
      }
    }
  };

  return (
    <div>
      {isLoading && <div>Uploading...</div>}

      <JoyDoc
        doc={doc}
        fieldSettings={fieldSettings}
        onChange={(changelog, updatedDoc) => {
          console.log('Document changed:', changelog);
          setDoc(updatedDoc);
          saveDocument(updatedDoc);
        }}
        onFocus={(params, e) => {
          console.log('Field focused:', params.fieldId);
          analytics.track('field_focused', params);
        }}
        onBlur={(params, e) => {
          console.log('Field blurred:', params.fieldId);
          validateField(params.fieldId);
        }}
        onUploadAsync={async (params, fileUploads) => {
          const uploadPromises = fileUploads.map(async (file) => {
            const uploadedFile = await uploadToS3(file);
            return {
              url: uploadedFile.url,
              fileName: uploadedFile.fileName,
              filePath: uploadedFile.filePath
            };
          });
          return await Promise.all(uploadPromises);
        }}
        onCaptureAsync={async (params) => {
          const barcodeData = await captureBarcode();
          return barcodeData;
        }}
        onError={(error) => {
          console.error('JoyDoc Error:', error);
          showError(error.message || 'An error occurred');
        }}
      />
    </div>
  );
};

```

## Best Practices

1. **Async Event Handlers**: Always use `async/await` for upload and capture events
2. **Error Handling**: Implement proper error handling in all async event handlers
3. **Loading States**: Show loading indicators during file uploads
4. **Validation**: Use `onBlur` for field validation
5. **Analytics**: Use `onFocus` and `onChange` for user interaction tracking
6. **File Management**: Implement proper cleanup in `onFileDelete` handlers
7. **Performance**: Debounce `onChange` events if needed for frequent updates
