corrad-bp/docs/form-javascript-api.md
Afiq 4425e912ab Enhance Form Script Engine with New Field Functions and Notification Improvements
- Added new functions to the FormScriptEngine for enhanced field manipulation: setFieldByLabel() for setting fields by their display label, and getFieldOptions() for retrieving available options for select, radio, and checkbox fields.
- Improved the setField() function to handle various field types more robustly, including select, radio, checkbox, and range inputs, with better event triggering for reactive updates.
- Enhanced notification functions (showSuccess, showError, showInfo) to utilize Vue Toastification for improved user feedback, including customizable options for toast notifications.
- Updated documentation in the form builder to reflect new field helper functions and their usage, improving developer guidance and usability.
2025-08-07 21:24:03 +08:00

12 KiB

Form JavaScript API - Enhanced setField for Option Fields

Overview

The Form JavaScript API provides powerful functions to interact with form fields dynamically. This document focuses on the enhanced setField functionality that properly handles option-based components like select dropdowns, radio buttons, and checkboxes.

Enhanced setField Function

The setField function has been enhanced to intelligently handle different field types, especially option-based components where users can set values by either the internal value or the display label.

Basic Usage

// Basic text field
setField('first_name', 'John');

// Number field
setField('age', 25);

// Email field
setField('email', 'john@example.com');

Option-Based Fields

Select Dropdown

For select dropdowns, you can set the value using either the internal value or the display label:

// Setting by value (recommended)
setField('country', 'us');

// Setting by label (will automatically find the corresponding value)
setField('country', 'United States');

Example form configuration:

{
  "type": "select",
  "props": {
    "name": "country",
    "label": "Country",
    "options": [
      { "label": "United States", "value": "us" },
      { "label": "Canada", "value": "ca" },
      { "label": "United Kingdom", "value": "uk" }
    ]
  }
}

Radio Button Groups

Radio buttons work similarly - you can set by value or label:

// Setting by value
setField('gender', 'male');

// Setting by label
setField('gender', 'Male');

Checkbox Groups

For checkboxes, you can set single values or arrays:

// Single checkbox (boolean)
setField('newsletter', true);

// Multiple checkboxes - by value
setField('interests', ['sports', 'technology']);

// Multiple checkboxes - by label
setField('interests', ['Sports', 'Technology']);

// Single checkbox value
setField('interests', 'sports');

Additional Helper Functions

setFieldByLabel

Explicitly set a field by its label (display text) instead of value:

// Explicitly set by label
setFieldByLabel('priority', 'High Priority');
setFieldByLabel('status', 'In Progress');

getFieldOptions

Get all available options for a field:

// Get all options for a select field
const countryOptions = getFieldOptions('country');
console.log(countryOptions);
// Output: [
//   { label: "United States", value: "us" },
//   { label: "Canada", value: "ca" },
//   { label: "United Kingdom", value: "uk" }
// ]

// Use with conditional logic
const priorities = getFieldOptions('priority');
if (priorities.length > 0) {
  setField('priority', priorities[0].value); // Set to first option
}

Practical Examples

Dynamic Field Updates Based on Selection

// When country changes, update state/province options
onFieldChange('country', function(newValue) {
  if (newValue === 'us') {
    // Set to a US state
    setField('state', 'california');
  } else if (newValue === 'ca') {
    // Set to a Canadian province
    setField('province', 'ontario');
  }
});

Conditional Option Setting

// Set different options based on user type
onFieldChange('user_type', function(userType) {
  if (userType === 'premium') {
    setField('support_level', 'priority');
    setFieldByLabel('notification_preference', 'Email + SMS');
  } else {
    setField('support_level', 'standard');
    setFieldByLabel('notification_preference', 'Email Only');
  }
});

Working with Multiple Selections

// Add to existing checkbox selections
const currentInterests = getField('interests') || [];
const allInterests = [...currentInterests, 'photography'];
setField('interests', allInterests);

// Set multiple checkboxes by label
setFieldByLabel('services', ['Consulting', 'Development', 'Support']);

Form Initialization

// Set default values when form loads
setField('country', 'us');
setFieldByLabel('language', 'English');
setField('notifications', ['email', 'sms']);

// Show success message
showSuccess('Form initialized with default values');

Error Handling

The enhanced setField provides helpful warnings when options are not found:

// If option doesn't exist, warning is logged to console
setField('country', 'invalid_country'); 
// Console: [FormScriptEngine] Option "invalid_country" not found in select field "country"

// Check if field exists before setting
const options = getFieldOptions('priority');
if (options.some(opt => opt.value === 'urgent')) {
  setField('priority', 'urgent');
} else {
  console.log('Urgent priority option not available');
}

Best Practices

  1. Use Values When Possible: Internal values are more reliable than labels
// Preferred
setField('status', 'active');

// Works but less reliable if labels change
setFieldByLabel('status', 'Active Status');
  1. Check Options Exist: Use getFieldOptions to verify options exist
const statuses = getFieldOptions('status');
if (statuses.some(opt => opt.value === 'pending')) {
  setField('status', 'pending');
}
  1. Handle Arrays for Multi-Select: Always use arrays for checkbox groups
// Correct for multiple checkboxes
setField('preferences', ['email', 'sms', 'push']);

// Also works for single selection
setField('preferences', ['email']);
  1. Use Descriptive Field Names: Makes scripts more maintainable
// Good
setField('notification_method', 'email');
setField('user_subscription_type', 'premium');

// Less clear
setField('field1', 'email');
setField('type', 'premium');

Migration from Basic setField

If you're upgrading from the basic setField implementation:

Before (Basic Implementation)

// Only worked reliably with simple text fields
setField('name', 'John');

// Option fields required manual DOM manipulation
const select = document.querySelector('[data-name="country"] select');
select.value = 'us';
select.dispatchEvent(new Event('change'));

After (Enhanced Implementation)

// Works with all field types automatically
setField('name', 'John');
setField('country', 'us');               // By value
setField('country', 'United States');    // By label
setFieldByLabel('priority', 'High');     // Explicit label setting

Summary

The enhanced setField function provides:

  • Smart option handling - works with select, radio, and checkbox fields
  • Flexible value setting - by internal value or display label
  • Array support - for multiple checkbox selections
  • Error handling - helpful warnings when options don't exist
  • Additional helpers - setFieldByLabel and getFieldOptions
  • Backward compatibility - existing scripts continue to work

This makes form scripting much more intuitive and powerful for complex forms with option-based fields.


JavaScript API Functions Summary

All the functions documented above are now available in the Form JavaScript API:

Core Form Functions

  • getField(fieldName) - Get field value
  • setField(fieldName, value) - Set field value (enhanced for options)
  • setFieldByLabel(fieldName, labelValue) - Set field by display label
  • getFieldOptions(fieldName) - Get available options for a field
  • hideField(fieldName) / showField(fieldName) - Control field visibility
  • disableField(fieldName) / enableField(fieldName) - Control field state
  • validateField(fieldName) - Trigger field validation
  • getAllFieldValues() - Get all form data
  • onFieldChange(fieldNames, callback) - Register field change handlers

Enhanced Alert Functions (Vue Toastification)

  • showSuccess(message, options) - Success notifications
  • showError(message, options) - Error notifications
  • showInfo(message, options) - Info notifications
  • showWarning(message, options) - Warning notifications
  • showToast(message, options) - Toast notifications with type support
  • showConfirm(message, options) - Confirmation dialogs with custom buttons (SweetAlert2)
  • showInputDialog(message, options) - Input dialogs with validation (SweetAlert2)
  • showSelectDialog(message, options) - Selection dialogs (SweetAlert2)
  • showProgress(message, options) - Progress dialogs (SweetAlert2)
  • showCustomAlert(options) - Fully customizable alerts (SweetAlert2)
  • closeAlert() - Close any open alert (SweetAlert2)
  • $toast - Direct access to Vue Toastification library

Usage Examples for showConfirm with Custom Buttons

// Basic confirmation with OK button
showConfirm('Are you sure you want to save?').then((result) => {
  if (result.isConfirmed) {
    // User clicked OK
    console.log('User confirmed');
  }
});

// Custom button labels
showConfirm('Delete this record?', {
  confirmButtonText: 'Yes, Delete',
  cancelButtonText: 'Keep It',
  title: 'Confirm Deletion'
}).then((result) => {
  if (result.isConfirmed) {
    showSuccess('Record deleted successfully!');
  }
});

// Custom colors and styling
showConfirm('This action cannot be undone', {
  title: 'Are you absolutely sure?',
  confirmButtonText: 'Delete Forever',
  cancelButtonText: 'Cancel',
  confirmButtonColor: '#d33',
  cancelButtonColor: '#3085d6',
  icon: 'warning'
});

// Single OK button (no cancel)
showConfirm('Please read the terms and conditions', {
  title: 'Important Notice',
  confirmButtonText: 'I Understand',
  showCancelButton: false,
  icon: 'info'
});

All functions support custom options and return promises for easy async handling!


Vue Toastification Integration

The notification functions now use Vue Toastification, which is already integrated in the project, providing beautiful and consistent toast notifications.

Basic Toast Usage

// Simple notifications
showSuccess('Form saved successfully!');
showError('Validation failed');
showInfo('Please review your entries');
showWarning('Some fields are incomplete');

// With custom options
showSuccess('Data updated!', {
  timeout: 5000,
  position: 'top-center'
});

// Different toast types
showToast('Custom message', { type: 'success' });
showToast('Warning message', { type: 'warning' });
showToast('Error message', { type: 'error' });

Available Toast Options

showSuccess('Message', {
  timeout: 3000,           // Auto-dismiss time (0 for no auto-dismiss)
  position: 'bottom-right', // Position: top-left, top-center, top-right, bottom-left, bottom-center, bottom-right
  closeOnClick: true,      // Close on click
  pauseOnFocusLoss: true,  // Pause timer when window loses focus
  pauseOnHover: true,      // Pause timer on hover
  draggable: true,         // Allow dragging to dismiss
  draggablePercent: 0.6,   // Percentage of drag needed to dismiss
  showCloseButtonOnHover: false, // Show close button only on hover
  hideProgressBar: false,  // Hide progress bar
  closeButton: "button",   // Close button type
  icon: true,             // Show icon
  rtl: false              // Right-to-left text direction
});

Direct Toast Access

For advanced usage, you can access the toast instance directly:

// Get direct access to Vue Toastification
const toast = $toast;

if (toast) {
  // Use all Vue Toastification methods
  toast.success('Success message');
  toast.error('Error message');
  toast.warning('Warning message');
  toast.info('Info message');
  
  // Clear all toasts
  toast.clear();
  
  // Update a toast
  const toastId = toast.success('Loading...', { timeout: false });
  // Later update it
  toast.update(toastId, { 
    content: 'Completed!', 
    options: { timeout: 3000, type: 'success' } 
  });
}

Integration Examples

// Form validation with toasts
onFieldChange('email', function(emailValue) {
  if (emailValue && !emailValue.includes('@')) {
    showWarning('Please enter a valid email address');
  }
});

// Success feedback after form actions
onFieldChange('save_draft', function(value) {
  if (value) {
    showSuccess('Draft saved successfully!', {
      position: 'top-center',
      timeout: 2000
    });
  }
});

// Error handling
try {
  // Some form operation
  setField('complex_field', calculatedValue);
  showInfo('Field updated automatically');
} catch (error) {
  showError('Failed to update field: ' + error.message);
}