Simple Real-World Patterns
Forsta HX Platform - API Scripting Guide
Simple Real-World Patterns (Forsta Standard)
Pattern 1: Sum Selected Checkboxes (Most Common)
// Calculate total spend from selected options - STANDARD PATTERN
var totalSpend = 0; // Initialize total
// Get array of all possible option codes (e.g., ["1", "2", "3"])
var codes = f('SpendQ').domainValues();
// Loop through each option code
for (var i = 0; i < codes.length; i++) {
// Check if this option is selected
if (f('SpendQ').item(codes[i]).toBoolean()) {
// Add this option's numeric value to the total
totalSpend += f('SpendQ').item(codes[i]).toNumber();
}
}
// Set the calculated total
f('TotalSpend').set(totalSpend);
Pattern 2: Check Specific Option and Show Follow-up
// If user selects option "3", show follow-up - Forsta method
// .item('3') accesses the option with code "3"
// .toBoolean() returns true if that option is selected
if (f('AQ1').item('3').toBoolean()) {
f('AQ1a').show(); // Show "Please explain" textbox (jQuery)
} else {
f('AQ1a').hide(); // Hide it (jQuery)
}
Pattern 3: Count Selections and Validate
// Ensure user selects 3-5 options - Forsta method
var codes = f('BQ2').domainValues(); // Get all option codes
var count = 0; // Initialize counter
// Count how many are selected
codes.forEach(function(code) {
if (f('BQ2').item(code).toBoolean()) {
count++; // Increment counter if selected
}
});
// Validate the count is in acceptable range
if (count < 3 || count > 5) {
alert('Please select between 3 and 5 options');
return false; // Validation failed
}
// Save the count and return success
f('SelectionCount').set(count);
return true;
Pattern 4: Calculate Weighted Score
// Calculate score with different weights - Forsta method
var codes = f('RatingQ').domainValues(); // Get all option codes
var weightedScore = 0; // Initialize weighted total
// Define weight multipliers for each option code
var weights = {'1': 1, '2': 2, '3': 3, '4': 5, '5': 8};
// Loop through each option
codes.forEach(function(code) {
// Check if this option is selected
if (f('RatingQ').item(code).toBoolean()) {
// Get the numeric value of the option
var value = f('RatingQ').item(code).toNumber();
// Multiply value by weight (use 1 if weight not found)
weightedScore += value * (weights[code] || 1);
}
});
// Save the weighted score
f('WeightedScore').set(weightedScore);
Pattern 5: Compare Two Questions
// Find options selected in both questions - Forsta method
var codes = f('PreQ').domainValues();
var matchCount = 0;
codes.forEach(function(code) {
var inPre = f('PreQ').item(code).toBoolean();
var inPost = f('PostQ').item(code).toBoolean();
if (inPre && inPost) {
matchCount++;
}
});
f('MatchingSelections').set(matchCount);
Pattern 6: Yes/No with Follow-up (jQuery for show/hide)
// Use Forsta to check value, jQuery to show/hide
f('AQ1').on('change', function() {
var value = f('AQ1').get(); // Get with Forsta
if (value == '1') {
f('AQ2').show(); // Show with jQuery
f('AQ3').show();
} else {
f('AQ2').hide(); // Hide with jQuery
f('AQ3').hide();
}
});
Pattern 7: Convert and Format Values
// Convert field value to string and format
if (f('userid').toBoolean()) {
var userID = f('userid').toString().toLowerCase();
var formattedID = userID + '-2024';
f('FormattedUserID').set(formattedID);
}
// Create utility function for formatting
function padNumber(num, length) {
var str = String(num);
while (str.length < length) {
str = "0" + str;
}
return str;
}
// Usage
var patientNum = 5;
var formatted = padNumber(patientNum, 3); // "005"
f('PatientID').set(formatted);
Pattern 8: Conditional Execution (Production vs Test)
// Only run code in production environment
if (IsInProductionMode()) {
// Production-only logic
if (f('userid').toBoolean()) {
var userID = f('userid').toString();
f('ProcessedUserID').set(userID.toUpperCase());
}
} else {
// Test environment - use dummy data
f('ProcessedUserID').set('TEST-USER-001');
}
Pattern 9: Loop Through Grid Rows and Set Values
// Set values for each row in a grid/loop question
// Get array of all row codes (e.g., ["1", "2", "3"])
var rows = f('GridQuestion').domainValues();
// Loop through each row
for (var i = 0; i < rows.length; i++) {
var rowNum = parseInt(rows[i]); // Convert row code to integer
// Generate a value for this specific row
var calculatedValue = 'Row-' + rowNum + '-Value';
// Set value for this specific row using .item(rowCode).set()
// .item(rows[i]) targets the specific row
// .set(calculatedValue) sets the value for that row
f('GridQuestion').item(rows[i]).set(calculatedValue);
}
// Alternative: Using forEach with conditional logic
rows.forEach(function(row) {
if (someCondition) { // Your condition here
var value = calculateValue(row); // Your calculation
// Set value for this row
f('GridQuestion').item(row).set(value);
}
});
Pattern 10: Environment-Specific Processing
// Different logic for test vs production
if (isTestID()) {
// Test ID - use test data
var testValue = 'TEST-' + Date.now();
f('ProcessedData').set(testValue);
}
else if (f('userid').toBoolean()) {
// Real user - process normally
var uid = f('userid').get();
var realValue = processUserData(uid);
f('ProcessedData').set(realValue);
}