@gov-cy/govcy-express-services
Version:
An Express-based system that dynamically renders services using @gov-cy/govcy-frontend-renderer and posts data to a submission API.
148 lines (131 loc) • 7.06 kB
JavaScript
/**
* @module govcyFormHandling
* @fileoverview This module provides utility functions for handling form data in a web application.
* It includes functions to populate form data with session data, handle conditional elements,
* and show error summary when there are validation errors.
*/
import { ALLOWED_FORM_ELEMENTS } from "./govcyConstants.mjs";
/**
* Helper function to populate form data with session data
* @param {Array} formElements The form elements
* @param {*} theData The data either from session or request
*/
export function populateFormData(formElements, theData, validationErrors) {
const inputElements = ALLOWED_FORM_ELEMENTS;
// Recursively populate form data with session data
formElements.forEach(element => {
if (inputElements.includes(element.element)) {
const fieldName = element.params.name;
// Handle `dateInput` separately
if (element.element === "dateInput") {
element.params.dayValue = theData[`${fieldName}_day`] || "";
element.params.monthValue = theData[`${fieldName}_month`] || "";
element.params.yearValue = theData[`${fieldName}_year`] || "";
//Handle `datePicker` separately
} else if (element.element === "datePicker") {
const val = theData[fieldName];
// Check if the value exists and matches the D/M/YYYY or DD/MM/YYYY pattern
if (val && /^\d{1,2}\/\d{1,2}\/\d{4}$/.test(val)) {
const [day, month, year] = val.split("/").map(Number); // Convert parts to numbers
const date = new Date(year, month - 1, day); // Month is zero-based in JS
// Check if the date is valid (e.g., not 31/02/2020)
if (
date.getFullYear() === year &&
date.getMonth() === month - 1 &&
date.getDate() === day
) {
// Format it as YYYY-MM-DD for the <input type="date"> value
const yyyy = year;
const mm = String(month).padStart(2, '0');
const dd = String(day).padStart(2, '0');
element.params.value = `${yyyy}-${mm}-${dd}`;
} else {
// Invalid date (e.g., 31/02/2020)
element.params.value = "";
}
} else {
// Invalid format (not matching D/M/YYYY or DD/MM/YYYY)
element.params.value = "";
}
// Handle all other input elements (textInput, checkboxes, radios, etc.)
} else {
element.params.value = theData[fieldName] || "";
}
// if there are validation errors, populate the error message
if (validationErrors?.errors?.[fieldName]) {
element.params.error = validationErrors.errors[fieldName].message;
//populate the error summary
const elementId = (element.element === "checkboxes" || element.element === "radios") // if checkboxes or radios
? `${element.params.id}-option-1` // use the id of the first option
: (element.element === "dateInput") //if dateInput
? `${element.params.id}_day` // use the id of the day input
: element.params.id; // else use the id of the element
validationErrors.errorSummary.push({
link: `#${elementId}`,
text: validationErrors.errors[fieldName].message
});
}
}
// Handle conditional elements inside radios
if (element.element === "radios" && element.params.items) {
element.params.items.forEach(item => {
if (item.conditionalElements) {
populateFormData(item.conditionalElements, theData, validationErrors);
// Check if any conditional element has an error and add to the parent "conditionalHasErrors": true
if (item.conditionalElements.some(condEl => condEl.params?.error)) {
item.conditionalHasErrors = true;
}
}
});
}
});
}
/**
* Filters form data based on the form definition, including conditionals.
*
* @param {Array} elements - The form elements (including conditional ones).
* @param {Object} formData - The submitted form data.
* @returns {Object} filteredData - The filtered form data.
*/
export function getFormData(elements, formData) {
const filteredData = {};
elements.forEach(element => {
const { name } = element.params || {};
// Check if the element is allowed and has a name
if (ALLOWED_FORM_ELEMENTS.includes(element.element) && name) {
// Handle conditional elements (e.g., checkboxes, radios, select)
if (["checkboxes", "radios", "select"].includes(element.element)) {
const value = formData[name];
filteredData[name] = value !== undefined && value !== null ? value : "";
// Process conditional elements inside items
if (element.element === "radios" && element.params.items) {
element.params.items.forEach(item => {
if (item.conditionalElements) {
Object.assign(
filteredData,
getFormData(item.conditionalElements, formData)
);
}
});
}
}
// Handle dateInput
else if (element.element === "dateInput") {
const day = formData[`${name}_day`];
const month = formData[`${name}_month`];
const year = formData[`${name}_year`];
filteredData[`${name}_day`] = day !== undefined && day !== null ? day : "";
filteredData[`${name}_month`] = month !== undefined && month !== null ? month : "";
filteredData[`${name}_year`] = year !== undefined && year !== null ? year : "";
// Handle other elements (e.g., textInput, textArea, datePicker)
} else {
filteredData[name] = formData[name] !== undefined && formData[name] !== null ? formData[name] : "";
}
// Always process conditional elements directly attached to the current element
// if (element.conditionalElements) {
// Object.assign(filteredData, getFormData(element.conditionalElements, formData));
// }
}
});
return filteredData;
}