Form Hooks API
Form Hooks API
Section titled “Form Hooks API”The Form component exposes an API through window.$useFormCore that allows external JavaScript to interact with form instances.
Accessing Hooks
Section titled “Accessing Hooks”// Hooks are available after form.js is loadedconst { onChange, setSpecInPath } = window.$useFormCore;Available Hooks
Section titled “Available Hooks”| Hook | Signature | Description |
|---|---|---|
onChange | (formId: string, callback: Function) => void | Subscribe to form value changes |
setSpecInPath | (formId: string, path: string, newSpec: Field) => void | Dynamically update form structure |
onChange
Section titled “onChange”Subscribe to value changes for a specific form instance.
Signature
Section titled “Signature”onChange( formId: string, callback: (event: CustomEvent<[string, any, string]>) => void): voidParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
formId | string | The unique ID of the form to subscribe to |
callback | Function | Called when any field value changes |
Callback Event Details
Section titled “Callback Event Details”The callback receives a CustomEvent with a detail array containing:
| Index | Type | Description |
|---|---|---|
detail[0] | string | Path of the changed field (e.g., "user.email") |
detail[1] | any | New value of the field |
detail[2] | string | Form ID |
Example
Section titled “Example”const { onChange } = window.$useFormCore;
onChange('my-form', (event) => { const [path, value, formId] = event.detail;
console.log(`Field "${path}" changed to:`, value); console.log('Form ID:', formId);
// React to specific field changes if (path === 'request.integration') { loadIntegrationDetails(value); }});Vue Example
Section titled “Vue Example”<script setup lang="ts">import { onMounted, onUnmounted } from 'vue';
const formId = 'dynamic-form';
onMounted(() => { const { onChange } = window.$useFormCore;
onChange(formId, (event) => { const [path, value] = event.detail;
// Auto-fill related fields if (path === 'address.zipCode' && value.length === 5) { fetchCityByZip(value); } });});</script>
<template> <form-component :id="formId" :spec="spec" /></template>setSpecInPath
Section titled “setSpecInPath”Dynamically replace a field’s specification at runtime. This allows you to:
- Change field types based on user selections
- Add/remove validation rules
- Update select options dynamically
- Modify labels or placeholders
Signature
Section titled “Signature”setSpecInPath( formId: string, path: string, newSpec: Field): voidParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
formId | string | The unique ID of the form |
path | string | Dot-notation path to the field (e.g., "request.body") |
newSpec | Field | New field specification to replace the existing one |
Example: Replacing a Field
Section titled “Example: Replacing a Field”const { setSpecInPath } = window.$useFormCore;
// Original spec had: { type: 'text', name: 'body', label: 'Body' }// Replace with a select field:
setSpecInPath('my-form', 'request.body', { type: 'select', name: 'body', label: 'Request Body Template', options: [ { label: 'JSON', value: 'json' }, { label: 'XML', value: 'xml' }, { label: 'Form Data', value: 'form' }, ],});Example: Dynamic Options Based on Selection
Section titled “Example: Dynamic Options Based on Selection”const { onChange, setSpecInPath } = window.$useFormCore;
// Listen for integration selectiononChange('action-form', (event) => { const [path, value] = event.detail;
if (path === 'request.integration') { // Load actions for selected integration const actions = await fetchIntegrationActions(value);
// Update the action select options setSpecInPath('action-form', 'request.action', { type: 'select', name: 'action', label: 'Action', required: true, options: actions.map(a => ({ label: a.name, value: a.id, description: a.description, })), }); }});Path Resolution
Section titled “Path Resolution”The path follows dot notation matching the name properties in your spec:
// Given this spec:const spec = { type: 'collection', name: 'request', spec: [ { type: 'text', name: 'url', label: 'URL', }, { type: 'collection', name: 'headers', spec: [ { type: 'text', name: 'contentType', label: 'Content-Type' }, ], }, ],};
// Paths would be:// - "request.url" -> the URL field// - "request.headers" -> the headers collection// - "request.headers.contentType" -> the Content-Type fieldComplete Integration Example
Section titled “Complete Integration Example”Here’s a complete example showing how to build a dynamic form that changes based on user selections:
<!DOCTYPE html><html><head> <script src="./dist/form.js"></script></head><body> <form-component id="integration-form"></form-component>
<script> // Initial spec with integration selector const initialSpec = { type: 'collection', name: 'config', spec: [ { type: 'select', name: 'provider', label: 'Provider', required: true, options: [ { label: 'Shopify', value: 'shopify' }, { label: 'WooCommerce', value: 'woocommerce' }, { label: 'Magento', value: 'magento' }, ], }, { type: 'text', name: 'credentials', label: 'API Key', placeholder: 'Select a provider first', readonly: true, }, ], };
// Set spec on form const form = document.getElementById('integration-form'); form.spec = JSON.stringify(initialSpec);
// Get hooks const { onChange, setSpecInPath } = window.$useFormCore;
// Provider-specific credential specs const providerSpecs = { shopify: { type: 'collection', name: 'credentials', spec: [ { type: 'text', name: 'shopName', label: 'Shop Name', required: true }, { type: 'password', name: 'apiKey', label: 'API Key', required: true }, { type: 'password', name: 'apiSecret', label: 'API Secret', required: true }, ], }, woocommerce: { type: 'collection', name: 'credentials', spec: [ { type: 'url', name: 'storeUrl', label: 'Store URL', required: true }, { type: 'password', name: 'consumerKey', label: 'Consumer Key', required: true }, { type: 'password', name: 'consumerSecret', label: 'Consumer Secret', required: true }, ], }, magento: { type: 'collection', name: 'credentials', spec: [ { type: 'url', name: 'baseUrl', label: 'Magento URL', required: true }, { type: 'password', name: 'accessToken', label: 'Access Token', required: true }, ], }, };
// Listen for provider changes onChange('integration-form', (event) => { const [path, value] = event.detail;
if (path === 'config.provider' && providerSpecs[value]) { // Replace credentials field with provider-specific spec setSpecInPath('integration-form', 'config.credentials', providerSpecs[value]); } });
// Handle form submission form.addEventListener('submit', (e) => { console.log('Integration configured:', e.detail); }); </script></body></html>TypeScript Declarations
Section titled “TypeScript Declarations”If you’re using TypeScript, you can add type declarations for the hooks:
import type { Field } from '@ion-components/ui/types';
declare global { interface Window { $useFormCore: { onChange: ( formId: string, callback: (event: CustomEvent<[string, any, string]>) => void ) => void;
setSpecInPath: ( formId: string, path: string, newSpec: Field ) => void; }; }}
export {};