Now.js Framework Documentation
FileElementFactory - File Upload Component
FileElementFactory - File Upload Component
Documentation for FileElementFactory, a powerful file upload component with preview, drag & drop, sorting, and validation capabilities.
📋 Table of Contents
- Overview
- Installation and Setup
- Basic Usage
- HTML Attributes
- Configuration Options
- Features
- File Validation
- Preview System
- Drag & Drop
- Sortable Files
- Existing Files
- Events
- JavaScript API
- Usage Examples
- Best Practices
Overview
FileElementFactory is an ElementFactory that enhances file input elements with advanced features like preview, drag & drop, file validation, sorting, and seamless integration with the Now.js Form component.
Key Features
- ✅ Live Preview: Real-time preview of uploaded images and files
- ✅ Drag & Drop: Intuitive drag and drop interface
- ✅ File Validation: Validate file types and sizes
- ✅ Sortable Files: Reorder files by dragging (requires Sortable.js)
- ✅ Multiple Files: Support for single and multiple file uploads
- ✅ Existing Files: Load and display existing files from server
- ✅ Remove Files: Delete files before submission
- ✅ Progress Tracking: Upload progress indicator
- ✅ Form Integration: Seamless integration with FormManager
- ✅ Auto-Initialization: Automatically enhances file inputs
When to Use FileElementFactory
✅ Use FileElementFactory when:
- You need file upload with preview
- You want drag and drop functionality
- You need to validate file types and sizes
- You want to display existing uploaded files
- You need sortable file lists
- You want seamless form integration
❌ Don't use FileElementFactory when:
- You need very basic file input (use native
<input type="file">) - You need custom upload logic (use custom implementation)
- You don't need any enhanced features
Installation and Setup
FileElementFactory is part of the Now.js Framework and is automatically registered with ElementManager.
Dependencies
- ElementFactory - Base class
- EventSystemManager - Event handling
- FormError - Error display
- Sortable.js (optional) - For sortable file lists
- MediaViewer (optional) - For image preview modal
Auto-Registration
// FileElementFactory is automatically registered
ElementManager.registerElement('file', FileElementFactory);
// All <input type="file"> elements are automatically enhancedBasic Usage
1. Simple File Upload
<input type="file"
id="avatar"
name="avatar"
accept="image/*">2. File Upload with Preview
<input type="file"
id="avatar"
name="avatar"
data-preview="true"
accept="image/*">3. Multiple Files with Drag & Drop
<input type="file"
id="files"
name="files"
multiple
data-preview="true"
data-drag-drop="true"
accept="image/*,application/pdf">4. Complete Example with All Features
<form data-form="upload">
<label for="files">Upload Files</label>
<span class="form-control icon-upload">
<input type="file"
id="files"
name="files"
multiple
data-preview="true"
data-drag-drop="true"
data-sortable="true"
data-allow-remove-existing="true"
data-file-reference="url"
data-max-file-size="5242880"
accept="image/*,application/pdf"
placeholder="Drag files here or click to browse">
</span>
</form>HTML Attributes
FileElementFactory supports these data attributes for configuration:
Basic Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
data-preview |
boolean | false |
Enable live preview of uploaded files |
data-drag-drop |
boolean | false |
Enable drag and drop functionality |
data-sortable |
boolean | false |
Allow reordering of uploaded files |
data-allow-remove-existing |
boolean | false |
Allow removal of existing uploaded files |
multiple |
boolean | false |
Allow multiple file selection |
accept |
string | * |
Allowed file types (e.g., "image/*,application/pdf") |
placeholder |
string | - | Placeholder text for drag & drop zone |
File Reference Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
data-file-reference |
string | 'id' |
Field name for file reference (e.g., "url", "id") |
data-attr |
string | - | Bind to data source (e.g., "value:files") |
data-files |
JSON | - | Existing files data |
Validation Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
data-max-file-size |
number | 10485760 |
Maximum file size in bytes (default: 10MB) |
required |
boolean | false |
Make file upload required |
Server Integration Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
data-action-url |
string | - | API endpoint for file operations (delete, sort) |
Preview Container Attribute
| Attribute | Type | Default | Description |
|---|---|---|---|
data-preview-container |
string | - | CSS selector for custom preview container |
Configuration Options
When creating an instance programmatically:
const instance = FileElementFactory.create(element, {
// Preview
preview: true,
previewContainer: '.custom-preview',
// Drag & Drop
dragDrop: true,
// Sortable
sortable: true,
// File Management
allowRemoveExisting: true,
fileReference: 'url',
// Validation
maxFileSize: 5 * 1024 * 1024, // 5MB
allowedMimeTypes: ['image/*', 'application/pdf'],
// Server Integration
actionUrl: '/api/files',
// Existing Files
existingFiles: [
{ url: 'files/photo.jpg', name: 'photo.jpg' },
{ url: 'files/document.pdf', name: 'document.pdf' }
],
// UI
placeholder: 'Drag files here or click to browse',
downloadEnabled: true,
// Callbacks
onChange: (files, element) => {
console.log('Files changed:', files);
},
onError: (error) => {
console.error('Error:', error);
}
});Features
1. Live Preview
Display thumbnails of uploaded files:
<input type="file"
name="images"
multiple
data-preview="true"
accept="image/*">Features:
- Image thumbnails for image files
- File icons for documents (PDF, Word, Excel, etc.)
- File name and size display
- Remove button for each file
2. Drag & Drop
Enable drag and drop file upload:
<input type="file"
name="files"
multiple
data-drag-drop="true"
placeholder="Drag files here or click to browse">Features:
- Visual drop zone
- Drag over feedback
- Multiple file drop support
- Click to browse fallback
3. Multiple Files
Upload multiple files at once:
<input type="file"
name="files"
multiple
data-preview="true">4. File Validation
Validate file types and sizes:
<input type="file"
name="avatar"
accept="image/jpeg,image/png,image/webp"
data-max-file-size="2097152">
<!-- Max size: 2MB -->Validation Rules:
- File type validation (MIME types and extensions)
- File size validation
- Automatic error display
- Form integration
5. Sortable Files
Reorder uploaded files by dragging (requires Sortable.js):
<input type="file"
name="gallery"
multiple
data-preview="true"
data-sortable="true"
data-action-url="/api/files/sort">Features:
- Drag handle for each file
- Visual feedback during sorting
- Auto-save order to server
- Revert on error
6. Existing Files
Load and display existing files from server:
<input type="file"
name="files"
multiple
data-preview="true"
data-attr="value:files"
data-file-reference="url"
data-allow-remove-existing="true"
data-action-url="/api/files">Server Response Format:
{
"data": {
"files": [
{
"url": "uploads/photo.jpg",
"name": "photo.jpg",
"size": 1258291
},
{
"url": "uploads/document.pdf",
"name": "document.pdf",
"size": 524288
}
]
}
}File Validation
Supported File Types
Default allowed MIME types:
allowedMimeTypes: [
'image/*',
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'text/plain',
'application/zip',
'application/x-zip-compressed'
]Custom Validation
<!-- Accept only images -->
<input type="file" accept="image/*">
<!-- Accept specific image types -->
<input type="file" accept="image/jpeg,image/png,image/webp">
<!-- Accept images and PDFs -->
<input type="file" accept="image/*,application/pdf">
<!-- Accept by extension -->
<input type="file" accept=".jpg,.jpeg,.png,.pdf">File Size Validation
<!-- Max 5MB -->
<input type="file" data-max-file-size="5242880">
<!-- Max 10MB (default) -->
<input type="file" data-max-file-size="10485760">Validation Errors
Errors are automatically displayed using FormError:
// Error messages are translated
"File size cannot exceed {maxsize}"
"File type not allowed"
"File is required"Preview System
Automatic Preview
Preview is automatically created when data-preview="true":
<span class="form-control icon-upload">
<input type="file"
name="files"
multiple
data-preview="true">
</span>Generated HTML:
<span class="form-control icon-upload">
<input type="file" name="files" multiple>
<div class="file-preview">
<div class="preview-item" data-file-name="photo.jpg">
<span class="image-preview" style="background-image: url(...)"></span>
<div class="file-info">photo.jpg (1.2 MB)</div>
<button type="button" class="icon-delete" title="Delete file"></button>
</div>
</div>
</span>Custom Preview Container
<input type="file"
name="files"
data-preview="true"
data-preview-container="#custom-preview">
<div id="custom-preview"></div>Preview Features
- Image Thumbnails: Background images for photos
- File Icons: Icons for documents (PDF, Word, Excel, ZIP)
- File Info: Name and size display
- Remove Button: Delete files before upload
- Click to View: Click images to open in modal (requires MediaViewer)
Drag & Drop
Basic Drag & Drop
<input type="file"
name="files"
multiple
data-drag-drop="true"
placeholder="Drag files here or click to browse">Generated Drop Zone
<div class="file-drop-zone">
<input type="file" name="files" multiple>
<div class="file-drop-content">
<div class="file-drop-message">Drag files here or click to browse</div>
</div>
<div class="file-preview">
<!-- Preview items -->
</div>
</div>CSS Classes
| Class | When Applied | Description |
|---|---|---|
file-drop-zone |
Always | Drop zone container |
drag-over |
During drag | File is being dragged over |
file-drop-content |
Always | Drop zone content area |
file-drop-message |
Always | Drop zone message |
Styling Example
.file-drop-zone {
border: 2px dashed #ccc;
border-radius: 8px;
padding: 20px;
text-align: center;
transition: all 0.3s;
}
.file-drop-zone.drag-over {
border-color: #007bff;
background-color: #f0f8ff;
}
.file-drop-message {
color: #666;
font-size: 16px;
padding: 40px 20px;
}Sortable Files
Enable Sortable
Requires Sortable.js library:
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
<input type="file"
name="gallery"
multiple
data-preview="true"
data-sortable="true"
data-action-url="/api/files/sort"
data-file-reference="id">Server-Side Sorting
When files are reordered, a POST request is sent to data-action-url:
Request:
{
"action": "sort",
"order": [
{ "id": "123", "position": 0 },
{ "id": "456", "position": 1 },
{ "id": "789", "position": 2 }
]
}Response:
{
"status": 200,
"message": "Sort order saved"
}Sortable Features
- Drag handle for each file
- Visual feedback during drag
- Auto-save to server
- Revert on error
- Success notification
Existing Files
Load Existing Files
Use data-attr and data-file-reference to load existing files:
<form data-form="settings" data-load-api="settings.php">
<input type="file"
name="files"
multiple
data-preview="true"
data-attr="value:files"
data-file-reference="url"
data-allow-remove-existing="true"
data-action-url="/api/files">
</form>Server Response Format
{
"data": {
"files": [
{
"id": "123",
"url": "uploads/photo.jpg",
"name": "photo.jpg",
"size": 1258291
},
{
"id": "456",
"url": "uploads/document.pdf",
"name": "document.pdf",
"size": 524288
}
]
}
}Delete Existing Files
When data-allow-remove-existing="true", users can delete existing files:
Request:
{
"action": "delete",
"url": "uploads/photo.jpg"
}Response:
{
"status": 200,
"message": "File deleted successfully"
}Events
FileElementFactory emits events through EventSystemManager:
Event Types
| Event | When | Detail |
|---|---|---|
file:change |
Files changed | {elementId, files} |
Listen to Events
Now.on('file:change', (data) => {
console.log('Files changed:', data.files);
console.log('Element ID:', data.elementId);
});Form Integration
FileElementFactory integrates with FormManager:
- Automatic validation on form submit
- File data included in form submission
- Error display integration
JavaScript API
Get Instance
// From element
const instance = ElementManager.getInstance(element);
// From ID
const element = document.getElementById('files');
const instance = ElementManager.getInstance(element);Instance Methods
// Clear all files
instance.clearFiles();
// Validate files
const isValid = instance.validateFiles();
// Upload files
const result = await instance.upload({
url: '/api/upload',
data: { userId: 123 }
});Static Methods
// Validate single file
await FileElementFactory.validateFile(file, config);
// Format file size
const size = FileElementFactory.formatFileSize(1258291);
// Returns: "1.2 MB"
// Get file icon class
const icon = FileElementFactory.getFileIcon('document.pdf');
// Returns: "icon-pdf"
// Check file type
const isValid = FileElementFactory.isValidFileType(file, ['image/*', 'application/pdf']);Upload Method
const result = await instance.upload({
url: '/api/upload', // Upload URL
data: { // Additional data
userId: 123,
category: 'photos'
}
});
if (result.success) {
console.log('Upload successful');
} else {
console.error('Upload failed:', result.message);
}Features:
- Progress tracking
- FormData creation
- Additional data support
- Error handling
- Promise-based
Usage Examples
Example 1: Simple Avatar Upload
<form data-form="profile" method="POST" action="/api/profile">
<label for="avatar">Profile Photo</label>
<span class="form-control icon-image">
<input type="file"
id="avatar"
name="avatar"
data-preview="true"
accept="image/*"
data-max-file-size="2097152"
placeholder="Choose your profile photo">
</span>
<button type="submit">Save Profile</button>
</form>Example 2: Multiple Files with Drag & Drop
<form data-form="documents" method="POST" action="/api/documents">
<label for="files">Upload Documents</label>
<span class="form-control icon-upload">
<input type="file"
id="files"
name="files"
multiple
data-preview="true"
data-drag-drop="true"
accept="image/*,application/pdf"
data-max-file-size="10485760"
placeholder="Drag files here or click to browse">
</span>
<button type="submit">Upload Files</button>
</form>Example 3: Sortable Gallery
<form data-form="gallery" data-load-api="/api/gallery">
<label for="photos">Photo Gallery</label>
<span class="form-control icon-image">
<input type="file"
id="photos"
name="photos"
multiple
data-preview="true"
data-drag-drop="true"
data-sortable="true"
data-allow-remove-existing="true"
data-file-reference="id"
data-action-url="/api/gallery"
data-attr="value:photos"
accept="image/*"
placeholder="Drag photos here">
</span>
<button type="submit">Save Gallery</button>
</form>Example 4: Programmatic Usage
const element = document.getElementById('files');
const instance = FileElementFactory.create(element, {
preview: true,
dragDrop: true,
sortable: true,
maxFileSize: 5 * 1024 * 1024,
allowedMimeTypes: ['image/*', 'application/pdf'],
onChange: (files) => {
console.log('Files selected:', files);
},
onError: (error) => {
console.error('Error:', error);
}
});
// Upload files
document.querySelector('button').addEventListener('click', async () => {
const result = await instance.upload({
url: '/api/upload',
data: { category: 'documents' }
});
if (result.success) {
alert('Upload successful!');
}
});Best Practices
1. Always Validate File Types
<!-- ✅ Good: Specific file types -->
<input type="file" accept="image/jpeg,image/png,image/webp">
<!-- ❌ Bad: No validation -->
<input type="file">2. Set Reasonable File Size Limits
<!-- ✅ Good: 5MB limit for images -->
<input type="file"
accept="image/*"
data-max-file-size="5242880">
<!-- ❌ Bad: Default 10MB might be too large -->
<input type="file" accept="image/*">3. Use Preview for Better UX
<!-- ✅ Good: Show preview -->
<input type="file"
data-preview="true"
accept="image/*">
<!-- ❌ Bad: No visual feedback -->
<input type="file" accept="image/*">4. Enable Drag & Drop for Multiple Files
<!-- ✅ Good: Drag & drop for multiple files -->
<input type="file"
multiple
data-drag-drop="true"
data-preview="true">
<!-- ❌ Bad: Multiple files without drag & drop -->
<input type="file" multiple>5. Provide Clear Placeholders
<!-- ✅ Good: Clear instructions -->
<input type="file"
data-drag-drop="true"
placeholder="Drag images here or click to browse (max 5MB)">
<!-- ❌ Bad: Generic placeholder -->
<input type="file" data-drag-drop="true">6. Handle Existing Files Properly
<!-- ✅ Good: Load and allow deletion -->
<input type="file"
data-attr="value:files"
data-file-reference="url"
data-allow-remove-existing="true"
data-action-url="/api/files">
<!-- ❌ Bad: No way to manage existing files -->
<input type="file" data-attr="value:files">7. Use Form Integration
<!-- ✅ Good: Integrated with form -->
<form data-form="upload" data-ajax-submit="true">
<input type="file" name="files" required>
<button type="submit">Upload</button>
</form>
<!-- ❌ Bad: Manual handling -->
<input type="file" id="files">
<button onclick="uploadFiles()">Upload</button>8. Provide Feedback
// ✅ Good: User feedback
const instance = FileElementFactory.create(element, {
onChange: (files) => {
console.log(`${files.length} file(s) selected`);
},
onError: (error) => {
alert('Error: ' + error.message);
}
});
// ❌ Bad: Silent errors
const instance = FileElementFactory.create(element, {});Common Patterns
Pattern 1: User Profile Photo
<form data-form="profile">
<div class="avatar-upload">
<label for="avatar">Profile Photo</label>
<span class="form-control">
<input type="file"
id="avatar"
name="avatar"
data-preview="true"
data-attr="value:avatar"
data-file-reference="url"
accept="image/*"
data-max-file-size="2097152">
</span>
</div>
</form>Pattern 2: Document Upload
<form data-form="documents">
<label for="files">Upload Documents</label>
<span class="form-control icon-upload">
<input type="file"
id="files"
name="files"
multiple
data-preview="true"
data-drag-drop="true"
accept="application/pdf,application/msword"
data-max-file-size="10485760"
placeholder="Drag PDF or Word documents here">
</span>
</form>Pattern 3: Image Gallery
<form data-form="gallery" data-load-api="/api/gallery">
<label for="images">Gallery Images</label>
<span class="form-control">
<input type="file"
id="images"
name="images"
multiple
data-preview="true"
data-drag-drop="true"
data-sortable="true"
data-allow-remove-existing="true"
data-file-reference="id"
data-action-url="/api/gallery"
data-attr="value:images"
accept="image/*"
placeholder="Drag images to upload">
</span>
</form>Troubleshooting
Files Not Uploading
Problem: Files selected but not uploading
Solution:
<!-- Ensure form has correct attributes -->
<form data-form="upload"
method="POST"
action="/api/upload"
data-ajax-submit="true">
<input type="file" name="files" multiple>
<button type="submit">Upload</button>
</form>Preview Not Showing
Problem: Preview not displaying
Solution:
<!-- Ensure data-preview is set -->
<input type="file" data-preview="true">
<!-- Or check if preview container exists -->
<input type="file"
data-preview="true"
data-preview-container="#preview">
<div id="preview"></div>Sortable Not Working
Problem: Cannot reorder files
Solution:
<!-- 1. Include Sortable.js -->
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
<!-- 2. Enable sortable -->
<input type="file"
data-sortable="true"
data-action-url="/api/files/sort">File Validation Errors
Problem: Valid files being rejected
Solution:
<!-- Check accept attribute -->
<input type="file" accept="image/*,application/pdf">
<!-- Check file size limit -->
<input type="file" data-max-file-size="10485760">API Reference Summary
Configuration
interface FileElementConfig {
// Display
preview: boolean;
previewContainer: string | null;
placeholder: string | null;
// Interaction
dragDrop: boolean;
sortable: boolean;
allowRemoveExisting: boolean;
downloadEnabled: boolean;
// Validation
maxFileSize: number;
allowedMimeTypes: string[];
// Data
fileReference: string;
existingFiles: FileData[];
// Server
actionUrl: string;
// Callbacks
onChange: (files: File[], element: HTMLElement) => void;
onError: (error: Error) => void;
}
interface FileData {
id?: string;
url: string;
name: string;
size?: number;
}Methods
class FileElementFactory {
// Instance Methods
clearFiles(): void;
validateFiles(): boolean;
upload(options: UploadOptions): Promise<UploadResult>;
// Static Methods
static validateFile(file: File, config: Config): Promise<boolean>;
static formatFileSize(bytes: number): string;
static getFileIcon(filename: string): string;
static isValidFileType(file: File, acceptedTypes: string[]): boolean;
}Related Documentation
- FormManager - Form handling and validation
- ElementFactory - Base class for element factories
- EventSystemManager - Event handling system
- File Upload Example - Complete working example