Skip to content

function ​

Run JavaScript in an action.

Function Action Object ​

KeyDescription
action'function'
functionstring javascript to be run. This JS is converted into a function and executed

Note: The function key can also be used in any other action that originates from the client. This means actions generated in a hook call do not get the function run when arriving at the server.

Javascript is placed on a single JSON value line, you must separate commands with a semicolon. Proper JSON escaping will always need to be applied.

Async/Await Support ​

Effective Version: 3.2.31+

Function actions now support async/await syntax, allowing you to write asynchronous code that pauses the action sequence until completion. This means you can fetch data, wait for timers, or perform any async operation while keeping your action chain in the correct order.

Basic Async Syntax ​

javascript
// Wait 2 seconds before continuing to next action
await new Promise(resolve => setTimeout(resolve, 2000));
model.status = 'Done waiting!';

The next action in your chain won't execute until this code completes.

Uses: ​

Functions are great for injecting small logic into any work flow.

Contexts function code executes with slightly different context to other Java Script in BetterForms.

To GetReference ThisDescription
windowwindowThe Browser JS window object, good for environmental control
formSchemaformSchemaContaining other sub objects like model etc
modelmodelThis is the uppermost model object regardless of sub objects like accordions etc.
appappThis will access the global app data model
action objectactionThe whole action object that contains this function. eg: action.options.path Some BetterForms Elements will merge additional options into theoptions key.
paramsparamsGlobal parameters from store
argsargsArguments passed via action.options.args
EventBusEventBusVue EventBus for component communication
as of ver 0.7.302
Site appapp (site app data model)

Examples ​

Basic Synchronous Example ​

json
{
  "action": "function",
  "function": "formSchema.model.nameFirst = 'Jerome'"
}

Async API Call Example ​

javascript
model.status = 'Loading...';

try {
  const response = await fetch('/api/user/123');
  const userData = await response.json();
  
  model.userName = userData.name;
  model.status = 'Loaded';
} catch (error) {
  model.status = 'Error: ' + error.message;
}

Complete Async Workflow Example ​

javascript
// Initialize
model.progress = 'Starting...';
model.errors = [];

try {
  // Step 1: Validate input
  model.progress = 'Validating...';
  await new Promise(resolve => setTimeout(resolve, 500));
  
  if (!model.email || !model.email.includes('@')) {
    model.errors.push('Valid email required');
    return;
  }
  
  // Step 2: Check if user exists
  model.progress = 'Checking user...';
  const checkResponse = await fetch('/api/user/check', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email: model.email })
  });
  const checkData = await checkResponse.json();
  
  if (checkData.exists) {
    model.errors.push('User already exists');
    return;
  }
  
  // Step 3: Create user
  model.progress = 'Creating user...';
  const createResponse = await fetch('/api/user/create', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      email: model.email,
      name: model.name
    })
  });
  const userData = await createResponse.json();
  
  // Success!
  model.progress = 'Complete!';
  model.userId = userData.id;
  model.success = true;
  
} catch (error) {
  model.progress = 'Failed';
  model.errors.push(error.message);
  console.error('User creation failed:', error);
}

Best Practices ​

✅ DO ​

  • Use try/catch for error handling in async operations
  • Update model properties to show progress to users
  • Use await for operations that need to complete before continuing
  • Return early on validation failures
  • Log errors for debugging

Error Handling & Debugging ​

Effective Version: 3.x.x+

When JavaScript inside a function action throws an error, BetterForms fires error code 10501 with detailed context to help you identify the failing action. The error includes:

FieldDescription
Error code10501
MessageexecuteFunction error in action "<name>": <original error message> — where <name> is action.name, falling back to action.action, or "unnamed"
Info objectA structured object with the fields below

Info object fields:

KeyDescription
actionThe action type (e.g. "function")
nameThe action name, if set on the action object
functionSnippetThe first 200 characters of the JavaScript that was being executed
stackThe full JavaScript stack trace
optionsThe action's options object (includes args and any other keys)

Catching Function Errors with Custom Error Handlers ​

You can add a custom error handler in your site's app.errorHandlers array to react to function action errors:

json
{
  "codes": ["10501"],
  "actions": {
    "action": "showAlert",
    "options": {
      "title": "Script Error",
      "text": "A function action encountered an error. Check the browser console for details.",
      "type": "error"
    }
  }
}

The error details (code, message, and info) are automatically injected into the action's options.error key, so your custom handler can access options.error.description.functionSnippet, options.error.description.stack, etc.

Debugging Tips ​

  • Name your actions: Add a name key to your function actions so the error message clearly identifies which action failed.
  • Check the browser console: The full structured info object is logged, including the code snippet and stack trace.
  • Use try/catch inside your function: For expected failure points, wrap your code in try/catch blocks to handle errors gracefully within the function itself rather than relying on the global error handler.
json
{
  "action": "function",
  "name": "calculateTotals",
  "function": "model.total = model.items.reduce((sum, item) => sum + item.price, 0);"
}

If model.items is undefined, the error message will read: executeFunction error in action "calculateTotals": Cannot read properties of undefined (reading 'reduce')

Code Style ​

Function results returned with a return statement are ignored.

Contexts function code executes with the context of the currently active form, if you have a modal displayed, then code runs in that modal's context.

Klai Studio documentation