Dynamic Form - Scripting Syntax

JSScriptFieldUtils API Reference

This document provides detailed descriptions and JavaScript code examples for the key functions available in JSScriptFieldUtils that are exposed to JavaScript scripts for dynamic form field manipulation.

Overview

JSScriptFieldUtils is a utility class exposed to JavaScript scripts running in the ClearScript V8 engine. It provides powerful functions for:

  • Updating form field properties
  • Managing field configuration
  • Retrieving field values from form data
  • Generating field data objects
  • Producing final script execution results

Available Functions

1. UpdateField

Updates a specific property of a field identified by fieldKey. All other properties remain unchanged.

Signature:

UpdateField(fieldKey, propertyName, propertyValue)

Parameters:

  • fieldKey (string): The unique identifier of the field to update
  • propertyName (string): The name of the property to update
  • propertyValue (any): The new value for the property

Supported Properties:

  • isVisible - Boolean visibility flag
  • isRequired - Boolean required flag
  • isReadOnly - Boolean read-only flag
  • label - Field label text
  • helpText - Help text for the field
  • placeholder - Placeholder text
  • displayOrder - Integer display order
  • fieldType - Field type (text, select, etc.)
  • dataType - Data type (string, int, boolean, etc.)
  • defaultValue - Default value (JSON)
  • options - Field options array
  • attributes - Additional attributes (JSON)
  • layoutConfig - Layout configuration (JSON)
  • errorMessages - Error messages (JSON)
  • metadata - Additional metadata (JSON)

Returns: The updated FormFieldDto object, or null if field not found.

JavaScript Examples:

// Example 1: Hide a field based on another field's value
const licenseType = utils.GetFieldValue('license_type', 'value');
if (licenseType === 'personal') {
    utils.UpdateField('company_name', 'isVisible', false);
    utils.UpdateField('company_name', 'isRequired', false);
} else {
    utils.UpdateField('company_name', 'isVisible', true);
    utils.UpdateField('company_name', 'isRequired', true);
}
// Example 2: Update field label dynamically
const userType = utils.GetFieldValue('user_type', 'value');
if (userType === 'business') {
    utils.UpdateField('email', 'label', 'Business Email Address');
    utils.UpdateField('email', 'placeholder', 'your.name@company.com');
} else {
    utils.UpdateField('email', 'label', 'Personal Email Address');
    utils.UpdateField('email', 'placeholder', 'your.email@example.com');
}
// Example 3: Make field read-only based on condition
const status = utils.GetFieldValue('order_status', 'value');
if (status === 'completed' || status === 'cancelled') {
    utils.UpdateField('order_amount', 'isReadOnly', true);
    utils.UpdateField('order_items', 'isReadOnly', true);
}
// Example 4: Update field options dynamically
const country = utils.GetFieldValue('country', 'value');
if (country === 'USA') {
    utils.UpdateField('state', 'options', [
        { value: 'CA', label: 'California' },
        { value: 'NY', label: 'New York' },
        { value: 'TX', label: 'Texas' }
    ]);
} else if (country === 'Canada') {
    utils.UpdateField('state', 'options', [
        { value: 'ON', label: 'Ontario' },
        { value: 'QC', label: 'Quebec' },
        { value: 'BC', label: 'British Columbia' }
    ]);
}
// Example 5: Update display order to reorder fields
utils.UpdateField('first_name', 'displayOrder', 1);
utils.UpdateField('last_name', 'displayOrder', 2);
utils.UpdateField('email', 'displayOrder', 3);
utils.UpdateField('phone', 'displayOrder', 4);

2. UpdateFieldConfig

Updates a specific property within a field's config object while keeping other config properties unchanged. This is used for validation rules, data source settings, and other configuration properties.

Signature:

UpdateFieldConfig(fieldKey, configPropertyName, propertyValue)

Parameters:

  • fieldKey (string): The unique identifier of the field
  • configPropertyName (string): The name of the config property to update
  • propertyValue (any): The new value for the config property

Supported Config Properties:

  • groupName - Field group name
  • minValue - Minimum numeric value
  • maxValue - Maximum numeric value
  • minLength - Minimum string length
  • maxLength - Maximum string length
  • regexPattern - Regular expression pattern for validation
  • validationRules - Custom validation rules (JSON)
  • fieldEvents - Field event handlers (JSON)
  • fieldDatasourceIntegrationId - Data source integration ID
  • fieldDatasourceTransformConfig - Data source transformation config

Returns: The updated FormFieldDto object, or null if field not found.

JavaScript Examples:

// Example 1: Update validation rules based on field value
const ageVerification = utils.GetFieldValue('age_verified', 'value');
if (ageVerification === true) {
    utils.UpdateFieldConfig('age', 'minValue', 18);
    utils.UpdateFieldConfig('age', 'maxValue', 120);
} else {
    utils.UpdateFieldConfig('age', 'minValue', 0);
    utils.UpdateFieldConfig('age', 'maxValue', 150);
}
// Example 2: Update regex pattern for phone validation
const country = utils.GetFieldValue('country', 'value');
if (country === 'USA') {
    utils.UpdateFieldConfig('phone', 'regexPattern', '^\\+1[0-9]{10}$');
} else if (country === 'UK') {
    utils.UpdateFieldConfig('phone', 'regexPattern', '^\\+44[0-9]{10}$');
}
// Example 3: Update string length constraints
const descriptionType = utils.GetFieldValue('description_type', 'value');
if (descriptionType === 'short') {
    utils.UpdateFieldConfig('description', 'minLength', 10);
    utils.UpdateFieldConfig('description', 'maxLength', 100);
} else if (descriptionType === 'detailed') {
    utils.UpdateFieldConfig('description', 'minLength', 50);
    utils.UpdateFieldConfig('description', 'maxLength', 1000);
}
// Example 4: Update group name for field organization
const userRole = utils.GetFieldValue('user_role', 'value');
if (userRole === 'admin') {
    utils.UpdateFieldConfig('permissions', 'groupName', 'Admin Settings');
    utils.UpdateFieldConfig('access_level', 'groupName', 'Admin Settings');
} else {
    utils.UpdateFieldConfig('permissions', 'groupName', 'User Settings');
    utils.UpdateFieldConfig('access_level', 'groupName', 'User Settings');
}
// Example 5: Update complex validation rules
utils.UpdateFieldConfig('password', 'validationRules', {
    requireUppercase: true,
    requireLowercase: true,
    requireNumbers: true,
    requireSpecialChars: true,
    minLength: 8,
    customMessage: 'Password must contain uppercase, lowercase, numbers, and special characters'
});

3. GetFieldValue

Finds and retrieves a field value from form data by fieldKey. Can navigate into nested data structures using dot notation.

Signature:

GetFieldValue(fieldKey, dataPath = null, formData = null)

Parameters:

  • fieldKey (string): The fieldKey to search for (e.g., "license_type")
  • dataPath (string, optional): Path within the field's data (e.g., "value", "label", "metadata.code")
  • formData (object, optional): Form data object or JSON string. If null, uses internal field data storage.

Returns: The field's data value, or null if not found.

JavaScript Examples:

// Example 1: Get simple field value
const licenseType = utils.GetFieldValue('license_type', 'value');
if (licenseType === 'commercial') {
    utils.UpdateField('insurance_required', 'isVisible', true);
}
// Example 2: Get nested property from field data
const selectedOption = utils.GetFieldValue('product_category', 'metadata.code');
const optionLabel = utils.GetFieldValue('product_category', 'label');

console.log(`Selected: ${optionLabel} (${selectedOption})`);
// Example 3: Get value from external form data
const formData = {
    fieldDatas: [
        { fieldKey: 'email', data: { value: 'user@example.com', verified: true } },
        { fieldKey: 'phone', data: { value: '+1234567890', verified: false } }
    ]
};

const email = utils.GetFieldValue('email', 'value', formData);
const emailVerified = utils.GetFieldValue('email', 'verified', formData);

if (!emailVerified) {
    utils.UpdateField('email_verification_notice', 'isVisible', true);
}
// Example 4: Get array element by index
// If field data is: { data: { items: ['apple', 'banana', 'orange'] } }
const secondItem = utils.GetFieldValue('fruit_list', 'items.1'); // Returns 'banana'
// Example 5: Conditional logic based on multiple field values
const country = utils.GetFieldValue('country', 'value');
const state = utils.GetFieldValue('state', 'value');
const city = utils.GetFieldValue('city', 'value');

if (country === 'USA' && state === 'CA' && city === 'San Francisco') {
    utils.UpdateField('tax_rate', 'defaultValue', 8.5);
    utils.UpdateFieldConfig('tax_rate', 'minValue', 8.0);
    utils.UpdateFieldConfig('tax_rate', 'maxValue', 9.0);
}
// Example 6: Get entire data object
const userData = utils.GetFieldValue('user_profile'); // Returns entire data object
console.log(JSON.stringify(userData, null, 2));

4. ConvertToFieldDataDto

Converts a JavaScript object to a FieldDataDto structure. This is an internal utility function but can be useful for understanding the expected format when creating field data.

Note: This function is primarily used internally by ProduceFinalResult but understanding its behavior helps when preparing data for script results.

Expected JavaScript Object Format:

// Format 1: Using "value" property
{
    fieldKey: 'license_type',
    fieldType: 'select',
    dataType: 'string',
    value: 'commercial',  // Will be converted to "data" property
    label: 'License Type'
}

// Format 2: Using "data" property
{
    fieldKey: 'license_type',
    fieldType: 'select',
    dataType: 'string',
    data: { value: 'commercial', code: 'COM' },
    label: 'License Type'
}

JavaScript Examples:

// Example 1: Creating field data objects for script result
const affectedFieldDatas = [
    {
        fieldKey: 'calculated_total',
        fieldType: 'number',
        dataType: 'decimal',
        value: 1250.50,
        label: 'Total Amount'
    },
    {
        fieldKey: 'tax_amount',
        fieldType: 'number',
        dataType: 'decimal',
        value: 125.05,
        label: 'Tax Amount'
    }
];

// These will be automatically converted by ProduceFinalResult
// Example 2: Creating complex nested field data
const affectedFieldDatas = [
    {
        fieldKey: 'order_summary',
        fieldType: 'custom',
        dataType: 'object',
        data: {
            subtotal: 1000.00,
            tax: 80.00,
            shipping: 15.00,
            total: 1095.00,
            items: [
                { id: 1, name: 'Product A', quantity: 2, price: 500.00 },
                { id: 2, name: 'Product B', quantity: 1, price: 500.00 }
            ]
        },
        label: 'Order Summary'
    }
];
// Example 3: Creating field data with metadata
const affectedFieldDatas = [
    {
        fieldKey: 'approval_status',
        fieldType: 'select',
        dataType: 'string',
        data: {
            value: 'approved',
            code: 'APV',
            timestamp: new Date().toISOString(),
            approver: 'john.doe@company.com'
        },
        label: 'Approval Status'
    }
];

5. ProduceFinalResult

Produces the final result containing affected fields and field data that should be returned from the script execution. This function must be called at the end of your JavaScript script to return the results to the C# host.

Signature:

ProduceFinalResult(affectedFields, affectedFieldDatas)

Parameters:

  • affectedFields (array): List or array of FormFieldDto objects that were affected by script execution
  • affectedFieldDatas (array): List or array of field data objects that were affected by script execution

Returns: A JSFieldScriptResponseDto containing the affected fields and field data.

JavaScript Examples:

// Example 1: Basic usage - return modified fields only
const affectedFields = [];
const affectedFieldDatas = [];

// Modify some fields
const field1 = utils.UpdateField('company_name', 'isVisible', true);
const field2 = utils.UpdateField('company_name', 'isRequired', true);

if (field1) affectedFields.push(field1);
if (field2) affectedFields.push(field2);

// Return the results
return utils.ProduceFinalResult(affectedFields, affectedFieldDatas);
// Example 2: Return both modified fields and calculated data
const affectedFields = [];
const affectedFieldDatas = [];

// Get input values
const quantity = utils.GetFieldValue('quantity', 'value');
const unitPrice = utils.GetFieldValue('unit_price', 'value');

// Update visibility
const totalField = utils.UpdateField('total_price', 'isVisible', true);
affectedFields.push(totalField);

// Calculate and create field data
const total = quantity * unitPrice;
affectedFieldDatas.push({
    fieldKey: 'total_price',
    fieldType: 'number',
    dataType: 'decimal',
    value: total,
    label: 'Total Price'
});

return utils.ProduceFinalResult(affectedFields, affectedFieldDatas);
// Example 3: Complex scenario with multiple field updates and calculations
const affectedFields = [];
const affectedFieldDatas = [];

// Get form values
const licenseType = utils.GetFieldValue('license_type', 'value');
const yearsExperience = utils.GetFieldValue('years_experience', 'value');
const hasViolations = utils.GetFieldValue('has_violations', 'value');

// Update field visibility based on license type
if (licenseType === 'commercial') {
    const field1 = utils.UpdateField('cdl_endorsements', 'isVisible', true);
    const field2 = utils.UpdateField('cdl_endorsements', 'isRequired', true);
    const field3 = utils.UpdateField('hazmat_certification', 'isVisible', true);
    
    affectedFields.push(field1, field2, field3);
} else {
    const field1 = utils.UpdateField('cdl_endorsements', 'isVisible', false);
    const field2 = utils.UpdateField('hazmat_certification', 'isVisible', false);
    
    affectedFields.push(field1, field2);
}

// Calculate insurance premium
let basePremium = licenseType === 'commercial' ? 500 : 200;
let experienceDiscount = yearsExperience >= 5 ? 0.15 : (yearsExperience >= 3 ? 0.10 : 0);
let violationPenalty = hasViolations ? 0.25 : 0;

let calculatedPremium = basePremium * (1 - experienceDiscount) * (1 + violationPenalty);

// Create field data for calculated premium
affectedFieldDatas.push({
    fieldKey: 'insurance_premium',
    fieldType: 'number',
    dataType: 'decimal',
    value: calculatedPremium.toFixed(2),
    label: 'Monthly Insurance Premium'
});

// Update premium field visibility
const premiumField = utils.UpdateField('insurance_premium', 'isVisible', true);
affectedFields.push(premiumField);

// Return all changes
return utils.ProduceFinalResult(affectedFields, affectedFieldDatas);
// Example 4: Validation scenario with error messages
const affectedFields = [];
const affectedFieldDatas = [];

const age = utils.GetFieldValue('age', 'value');
const country = utils.GetFieldValue('country', 'value');

// Age validation based on country
let minAge = 18; // default
if (country === 'USA') minAge = 21;
else if (country === 'Japan') minAge = 20;

if (age < minAge) {
    // Update error message
    const ageField = utils.UpdateField('age', 'errorMessages', {
        custom: `You must be at least ${minAge} years old in ${country}`
    });
    affectedFields.push(ageField);
    
    // Create validation result field data
    affectedFieldDatas.push({
        fieldKey: 'age_validation_result',
        fieldType: 'text',
        dataType: 'string',
        value: 'invalid',
        label: 'Age Validation'
    });
} else {
    affectedFieldDatas.push({
        fieldKey: 'age_validation_result',
        fieldType: 'text',
        dataType: 'string',
        value: 'valid',
        label: 'Age Validation'
    });
}

return utils.ProduceFinalResult(affectedFields, affectedFieldDatas);
// Example 5: Multi-step form progression
const affectedFields = [];
const affectedFieldDatas = [];

const currentStep = utils.GetFieldValue('current_step', 'value') || 1;
const isStep1Complete = utils.GetFieldValue('step1_complete', 'value');
const isStep2Complete = utils.GetFieldValue('step2_complete', 'value');

// Show/hide steps based on completion
if (currentStep === 2 && isStep1Complete) {
    affectedFields.push(
        utils.UpdateField('step2_section', 'isVisible', true),
        utils.UpdateField('step1_section', 'isVisible', false)
    );
} else if (currentStep === 3 && isStep2Complete) {
    affectedFields.push(
        utils.UpdateField('step3_section', 'isVisible', true),
        utils.UpdateField('step2_section', 'isVisible', false)
    );
}

// Update progress indicator
affectedFieldDatas.push({
    fieldKey: 'form_progress',
    fieldType: 'custom',
    dataType: 'object',
    data: {
        currentStep: currentStep,
        totalSteps: 3,
        percentComplete: (currentStep / 3) * 100,
        completedSteps: [isStep1Complete, isStep2Complete].filter(x => x).length
    },
    label: 'Form Progress'
});

return utils.ProduceFinalResult(affectedFields, affectedFieldDatas);

Complete Working Example

Here's a complete JavaScript script that demonstrates all the functions together:

// Complete example: Dynamic insurance quote calculator

const affectedFields = [];
const affectedFieldDatas = [];

// Step 1: Get input values using GetFieldValue
const licenseType = utils.GetFieldValue('license_type', 'value');
const age = utils.GetFieldValue('driver_age', 'value');
const yearsLicensed = utils.GetFieldValue('years_licensed', 'value');
const hasAccidents = utils.GetFieldValue('has_accidents', 'value');
const vehicleType = utils.GetFieldValue('vehicle_type', 'value');

// Step 2: Update field visibility and requirements using UpdateField
if (licenseType === 'commercial') {
    affectedFields.push(
        utils.UpdateField('commercial_vehicle_type', 'isVisible', true),
        utils.UpdateField('commercial_vehicle_type', 'isRequired', true),
        utils.UpdateField('cargo_type', 'isVisible', true),
        utils.UpdateField('cargo_type', 'isRequired', true)
    );
    
    // Update labels
    affectedFields.push(
        utils.UpdateField('vehicle_type', 'label', 'Commercial Vehicle Class')
    );
} else {
    affectedFields.push(
        utils.UpdateField('commercial_vehicle_type', 'isVisible', false),
        utils.UpdateField('cargo_type', 'isVisible', false)
    );
}

// Step 3: Update validation rules using UpdateFieldConfig
if (licenseType === 'commercial') {
    affectedFields.push(
        utils.UpdateFieldConfig('driver_age', 'minValue', 21),
        utils.UpdateFieldConfig('years_licensed', 'minValue', 2)
    );
} else {
    affectedFields.push(
        utils.UpdateFieldConfig('driver_age', 'minValue', 18),
        utils.UpdateFieldConfig('years_licensed', 'minValue', 0)
    );
}

// Step 4: Calculate insurance quote
let baseRate = licenseType === 'commercial' ? 800 : 300;

// Age adjustment
if (age < 25) baseRate *= 1.5;
else if (age > 65) baseRate *= 1.2;

// Experience discount
let experienceDiscount = 0;
if (yearsLicensed >= 10) experienceDiscount = 0.20;
else if (yearsLicensed >= 5) experienceDiscount = 0.15;
else if (yearsLicensed >= 3) experienceDiscount = 0.10;

// Accident penalty
let accidentPenalty = hasAccidents ? 0.30 : 0;

// Vehicle type adjustment
let vehicleMultiplier = 1.0;
if (vehicleType === 'sports_car') vehicleMultiplier = 1.5;
else if (vehicleType === 'suv') vehicleMultiplier = 1.2;
else if (vehicleType === 'sedan') vehicleMultiplier = 1.0;

// Calculate final premium
const monthlyPremium = baseRate * (1 - experienceDiscount) * (1 + accidentPenalty) * vehicleMultiplier;
const annualPremium = monthlyPremium * 12;

// Step 5: Create calculated field data
affectedFieldDatas.push(
    {
        fieldKey: 'monthly_premium',
        fieldType: 'number',
        dataType: 'decimal',
        value: monthlyPremium.toFixed(2),
        label: 'Monthly Premium'
    },
    {
        fieldKey: 'annual_premium',
        fieldType: 'number',
        dataType: 'decimal',
        value: annualPremium.toFixed(2),
        label: 'Annual Premium'
    },
    {
        fieldKey: 'quote_details',
        fieldType: 'custom',
        dataType: 'object',
        data: {
            baseRate: baseRate,
            experienceDiscount: experienceDiscount,
            accidentPenalty: accidentPenalty,
            vehicleMultiplier: vehicleMultiplier,
            calculatedAt: new Date().toISOString()
        },
        label: 'Quote Calculation Details'
    }
);

// Step 6: Show results section
affectedFields.push(
    utils.UpdateField('quote_results_section', 'isVisible', true),
    utils.UpdateField('monthly_premium', 'isVisible', true),
    utils.UpdateField('annual_premium', 'isVisible', true)
);

// Step 7: Return final results using ProduceFinalResult
return utils.ProduceFinalResult(affectedFields, affectedFieldDatas);

Best Practices

  1. Always check for null: Field lookups can return null, so check before using values

    const value = utils.GetFieldValue('field_key', 'value');
    if (value !== null) {
        // Use value safely
    }
    
  2. Collect all changes before returning: Build arrays of affected fields and data throughout your script

    const affectedFields = [];
    const affectedFieldDatas = [];
    // ... make changes, push to arrays ...
    return utils.ProduceFinalResult(affectedFields, affectedFieldDatas);
    
  3. Use meaningful variable names: Make your scripts readable and maintainable

    const licenseType = utils.GetFieldValue('license_type', 'value');
    // Better than: const lt = utils.GetFieldValue('license_type', 'value');
    
  4. Handle edge cases: Always consider what happens when values are missing or unexpected

    const age = utils.GetFieldValue('age', 'value') || 0;
    if (age >= 18) {
        // Safe to proceed
    }
    
  5. Return results: Always end your script with return utils.ProduceFinalResult(...)

    return utils.ProduceFinalResult(affectedFields, affectedFieldDatas);
    

Error Handling

If an error occurs during script execution, the host application will catch it and return an appropriate error response. However, you should still handle potential issues in your script:

try {
    const affectedFields = [];
    const affectedFieldDatas = [];
    
    // Your logic here
    const value = utils.GetFieldValue('some_field', 'value');
    if (value === null) {
        console.log('Warning: Field value not found');
        // Handle gracefully
    }
    
    // ... rest of your logic ...
    
    return utils.ProduceFinalResult(affectedFields, affectedFieldDatas);
} catch (error) {
    console.error('Script error:', error.message);
    // Return empty result on error
    return utils.ProduceFinalResult([], []);
}

Additional Resources


Last Updated: November 23, 2025