### Server-Side Error Logging Examples Source: https://github.com/apostrophecms/form/blob/main/_autodocs/errors.md Examples of using `self.apos.util.error` and `self.apos.util.warn` for logging different types of errors and warnings on the server-side. ```javascript self.apos.util.error('reCAPTCHA submission error', e); self.apos.util.error('⚠️ @apostrophecms/form submission email notification error: ', err); ``` ```javascript self.apos.util.error(error); ``` ```javascript self.apos.util.warn(req.t('aposForm:fileMissingEarly', { path: file })); ``` -------------------------------- ### Client-side Form Submission Example Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Prepare and send form data from the client to the server for processing. Includes JSON data and file uploads. ```javascript // Client-side form submission const formElement = document.querySelector('form'); const formData = new FormData(formElement); const jsonData = { _id: formElement.dataset.formId, fieldName: formElement.querySelector('input[name="fieldName"]').value, // ... additional fields }; formData.append('data', JSON.stringify(jsonData)); // Server-side (via API endpoint) // POST /api/v1/@apostrophecms/form/submit ``` -------------------------------- ### Submission Data with Captured Query Parameters Source: https://github.com/apostrophecms/form/blob/main/_autodocs/endpoints.md Example of submission data including captured query parameters from the URL. ```javascript { _id: 'form-123', email: 'user@example.com', queryParams: { source: 'email-campaign', campaign: 'summer2024' } } ``` -------------------------------- ### Radio Field Configuration Example Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/field-widgets.md Shows the configuration for a radio button field, including its label, name, requirement status, and available choices. ```javascript // Form field configuration { fieldLabel: 'How did you hear about us?', fieldName: 'source', required: true, choices: [ { label: 'Search Engine', value: 'search' }, { label: 'Social Media', value: 'social' }, { label: 'Word of Mouth', value: 'referral' } ] } // Output { source: 'search' // Single value } ``` -------------------------------- ### Email Condition Value Matching Examples Source: https://github.com/apostrophecms/form/blob/main/_autodocs/types.md Illustrates how to specify single or multiple values for email condition matching, including handling values with commas. ```javascript // Single value value: "yes" // Multiple values (OR logic) value: "option1, option2, option3" // Quoted values with commas value: '"value, with, commas", "another, value"' ``` -------------------------------- ### Form Query Parameter Setup Source: https://github.com/apostrophecms/form/blob/main/modules/@apostrophecms/form-widget/views/widgetBase.html This code block demonstrates how to construct a comma-separated string of query parameter keys if they are defined for the form. This is used for passing parameters to the form. ```html {% if form %} {% set params = false %} {% if form.queryParamList %} {% set params = '' %} {% for param in form.queryParamList %} {% if loop.last %} {% set params = params + param.key %} {% else %} {% set params = params + param.key + ',' %} {% endif %} {% endfor %} {% endif %} ``` -------------------------------- ### Form Widget Configuration Example Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/field-widgets.md Demonstrates how to embed a form into a page or rich-text area using the form widget. It references a form document via a relationship. ```javascript // Form widget configuration in a page/rich-text area { type: '@apostrophecms/form-widget', _form: [ { _id: 'form-document-id', title: 'Contact Us' } ] } ``` -------------------------------- ### Environment Variables for reCAPTCHA Keys Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/recaptcha.md Example of how to export reCAPTCHA site and secret keys as environment variables. These are used in the module-level configuration. ```bash export RECAPTCHA_SECRET_KEY='6Lc_...secret...' export RECAPTCHA_SITE_KEY='6Lc_...site...' ``` -------------------------------- ### Text Field Sanitization Example Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/field-widgets.md Demonstrates the configuration and expected output for a text field widget, specifically an email input type, after sanitization. ```javascript // Form field configuration { fieldLabel: 'Email Address', fieldName: 'email', inputType: 'email', required: true, placeholder: 'user@example.com' } // Submission data { email: 'user@example.com' } // Output after sanitization { email: 'user@example.com' // Laundered as string } ``` -------------------------------- ### Boolean Field Sanitization Example Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/field-widgets.md Shows the configuration for a boolean field widget (e.g., a checkbox) and its expected sanitized output as a boolean value. ```javascript // Form field configuration { fieldLabel: 'I agree to the terms', fieldName: 'agreeToTerms', required: true } // Output after sanitization { agreeToTerms: true // Laundered as boolean } ``` -------------------------------- ### Select Field Sanitization Example Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/field-widgets.md Demonstrates how input values for a select field are sanitized against the provided choices. Invalid selections are filtered out. ```javascript // Form field configuration { fieldLabel: 'Country', fieldName: 'country', required: true, choices: [ { label: 'United States', value: 'us' }, { label: 'Canada', value: 'ca' }, { label: 'Mexico', value: 'mx' } ] } // Output after sanitization { country: 'us' // Laundered against choices array } ``` -------------------------------- ### Configure Form Module with Environment Variables Source: https://github.com/apostrophecms/form/blob/main/_autodocs/configuration.md Example of how to configure the '@apostrophecms/form' module in `app.js` using environment variables for reCAPTCHA keys and submission settings. ```javascript const apos = require('apostrophe'); apos.launch({ shortName: 'my-site', modules: { '@apostrophecms/form': { recaptchaSecret: process.env.RECAPTCHA_SECRET, recaptchaSite: process.env.RECAPTCHA_SITE, emailSubmissions: process.env.FORM_EMAIL !== 'false', saveSubmissions: process.env.FORM_SAVE !== 'false' } } }); ``` -------------------------------- ### Group Widget Configuration Example Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/field-widgets.md Illustrates the configuration of a group widget, used to visually group related form fields under a common label. Nested groups are not permitted. ```javascript // Group widget configuration { type: '@apostrophecms/form-group', label: 'Contact Information', contents: { items: [ { type: '@apostrophecms/form-text-field', fieldLabel: 'Name', fieldName: 'name' }, { type: '@apostrophecms/form-text-field', fieldLabel: 'Email', fieldName: 'email', inputType: 'email' } ] } } ``` -------------------------------- ### Add Image Widget to Thank You Message Source: https://github.com/apostrophecms/form/blob/main/_autodocs/configuration.md Example of how to add the image widget to the available widgets for the post-submission thank you message. ```javascript { thankYouWidgets: { '@apostrophecms/rich-text': { toolbar: ['styles', 'bold', 'italic', 'link'] }, '@apostrophecms/image': {} } } ``` -------------------------------- ### Client-Side reCAPTCHA Implementation Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/recaptcha.md This HTML and JavaScript example shows how to load the reCAPTCHA API, generate a token before form submission, and include it in the form data. It handles form submission using fetch API. ```html
``` -------------------------------- ### Configure Form Module Options Source: https://github.com/apostrophecms/form/blob/main/_autodocs/configuration.md Pass module options when configuring the form module in your project's `modules` configuration. This example shows common settings like reCAPTCHA keys and submission handling. ```javascript // app.js or modules/@apostrophecms/form/index.js module.exports = { // ... module definition ... options: { recaptchaSecret: 'your-secret-key-here', recaptchaSite: 'your-site-key-here', emailSubmissions: true, saveSubmissions: true, classPrefix: 'my-form', testing: false } } ``` -------------------------------- ### Example of CSS Class Prefix Usage in Template Source: https://github.com/apostrophecms/form/blob/main/_autodocs/configuration.md This HTML snippet demonstrates how the `classPrefix` option is used in a template to prepend a custom prefix to form element classes. ```html
``` -------------------------------- ### Textarea Field Sanitization Example Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/field-widgets.md Illustrates the configuration and sanitized output for a textarea field widget, suitable for longer text inputs. The input is laundered as a string. ```javascript // Form field configuration { fieldLabel: 'Message', fieldName: 'message', required: true, placeholder: 'Enter your message here...' } // Output after sanitization { message: 'User\'s multi-line message' // Laundered as string } ``` -------------------------------- ### Submission Data for Conditional Emails Source: https://github.com/apostrophecms/form/blob/main/_autodocs/endpoints.md Example of submission data that would trigger conditional emails based on the 'requestType' field. ```javascript { _id: 'form-123', requestType: 'Sales Inquiry', message: 'I am interested in pricing' } ``` -------------------------------- ### Handling Missing reCAPTCHA Token Source: https://github.com/apostrophecms/form/blob/main/_autodocs/errors.md This example shows how to ensure a reCAPTCHA token is generated and included in the submission data. It's crucial for forms with reCAPTCHA enabled to prevent 'recaptcha' errors. ```javascript // Ensure reCAPTCHA token is generated before submission const token = await grecaptcha.execute('site-key', { action: 'submit' }); if (!token) { console.error('Failed to generate reCAPTCHA token'); return; } // Add token to submission data submissionData.recaptcha = token; ``` -------------------------------- ### Conditional Widget Configuration Example Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/field-widgets.md Demonstrates how to configure a conditional widget to show or hide child fields based on another field's value. The 'state' field is only required if the 'country' field is 'us'. ```javascript // Conditional widget configuration { type: '@apostrophecms/form-conditional', conditionName: 'country', conditionValue: 'us', contents: { items: [ { type: '@apostrophecms/form-text-field', fieldLabel: 'State', fieldName: 'state', required: true } ] } } // Submission logic // If form input has country='us', the 'state' field is required // If form input has country='ca', the 'state' field is skipped ``` -------------------------------- ### Checkboxes Field Sanitization Example Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/field-widgets.md Illustrates the sanitization process for a checkboxes field, which handles an array of selected values and ensures they are valid choices. ```javascript // Form field configuration { fieldLabel: 'Interests', fieldName: 'interests', choices: [ { label: 'Technology', value: 'tech' }, { label: 'Sports', value: 'sports' }, { label: 'Arts', value: 'arts' } ] } // Submission data { interests: ['tech', 'arts'] } // Output after sanitization { interests: ['tech', 'arts'] // Array of valid choices } ``` -------------------------------- ### Database Indexes for Form Submissions Source: https://github.com/apostrophecms/form/blob/main/_autodocs/README.md These are examples of database indexes used for efficient querying of form submissions. They allow for retrieval of submissions sorted by form ID and creation date, either chronologically or in reverse. ```javascript { formId: 1, createdAt: 1 } ``` ```javascript { formId: 1, createdAt: -1 } ``` -------------------------------- ### Throwing a Form Not Found Error Source: https://github.com/apostrophecms/form/blob/main/_autodocs/errors.md Example of how to programmatically throw a 'notfound' error when a form submission is attempted for a non-existent form ID. This is checked early in the submission process. ```javascript if (!form) { throw self.apos.error('notfound'); } ``` -------------------------------- ### ApostropheCMS Form Widget Base Template Logic Source: https://github.com/apostrophecms/form/blob/main/modules/@apostrophecms/form-widget/views/widgetBase.html This snippet shows the initial setup and variable declarations for the ApostropheCMS form widget's base template. It retrieves widget data, form details, and configuration for reCAPTCHA. ```html {% set widget = data.widget %} {% set form = data.widget._form[0] %} {% set classPrefix = data.widget.classPrefix %} {% set prependIfPrefix = apos.modules['@apostrophecms/form'].prependIfPrefix %} {% set recaptchaSite = apos.modules['@apostrophecms/form'].options.recaptchaSite or (data.global.useRecaptcha and data.global.recaptchaSite) %} {% set recaptchaReady = form.enableRecaptcha and recaptchaSite %} ``` -------------------------------- ### Match File Names for Multiple Uploads Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/submission-handling.md This method checks if a given string starts with a specified name and ends with a numerical pattern (e.g., '-1', '-2'). This is used to support multiple file uploads for a single form field. ```javascript matchesName(str, name) { return str.startsWith(name) && str.match(/.+-\d+$/); } ``` -------------------------------- ### Restrict Form Widgets Source: https://github.com/apostrophecms/form/blob/main/_autodocs/configuration.md Configure the `formWidgets` option to replace the default set of field widgets. This example restricts the available fields to text, textarea, and a custom button widget. ```javascript { formWidgets: { '@apostrophecms/form-text-field': {}, '@apostrophecms/form-textarea-field': {}, '@apostrophecms/form-button': {} // Custom widget } } ``` -------------------------------- ### Clean reCAPTCHA Options Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/recaptcha.md Validates reCAPTCHA configuration, ensuring both secret and site keys are present. If either is missing, both are removed to prevent partial setup. ```javascript if (!options.recaptchaSecret || !options.recaptchaSite) { delete options.recaptchaSite; delete options.recaptchaSecret; } ``` ```javascript // Configuration with both keys - valid const opts1 = { recaptchaSecret: 'secret-key', recaptchaSite: 'site-key' }; self.cleanOptions(opts1); // Result: both keys remain // Configuration with only secret - invalid const opts2 = { recaptchaSecret: 'secret-key' }; self.cleanOptions(opts2); // Result: recaptchaSecret is deleted, no reCAPTCHA ``` -------------------------------- ### Get reCAPTCHA Secret Key Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/recaptcha.md Retrieves the reCAPTCHA secret key, checking module options first and then global settings. Returns null if no configuration is found. ```javascript const secret = await self.getRecaptchaSecret(req, self); if (secret) { // reCAPTCHA is enabled and configured } ``` -------------------------------- ### Get Choice Values from Widget Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/field-widgets.md Extracts an array of choice values from a widget configuration, typically used for select-type fields. Returns an array of strings. ```javascript const choices = self.getChoicesValues(selectWidget); // Returns: ['option1', 'option2', 'option3'] ``` -------------------------------- ### Throwing Field Sanitization Errors Source: https://github.com/apostrophecms/form/blob/main/_autodocs/errors.md This example demonstrates how to throw a custom 'invalid' error with specific field error data during form field sanitization on the server-side. This allows for detailed client-side error reporting. ```javascript throw self.apos.error('invalid', { fieldError: { field: widget.fieldName, error: string, message: req.t('aposForm:...') } }); ``` -------------------------------- ### Extend Form Module with Custom Submission Handlers Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/submission-handling.md This example shows how to extend the ApostropheCMS form module to add custom submission handlers like validation or webhook integration. Handlers are executed in registration order after built-in logic. ```javascript module.exports = { extend: '@apostrophecms/form', handlers(self) { return { submission: { async customValidator(req, form, data) { // Custom validation logic if (!isValid(data)) { throw self.apos.error('invalid', { fieldError: { field: 'fieldName', error: 'custom', message: 'Custom error' } }); } }, async sendWebhook(req, form, data) { // Send submission to external webhook await fetch('https://example.com/webhook', { method: 'POST', body: JSON.stringify(data) }); } } }; } }; ``` -------------------------------- ### Override Piece-Type Configuration Source: https://github.com/apostrophecms/form/blob/main/_autodocs/configuration.md Extend the '@apostrophecms/form' module to override default piece-type options. This example enables SEO fields. ```javascript module.exports = { extend: '@apostrophecms/form', options: { seoFields: true // Override default } } ``` -------------------------------- ### Module Configuration Options Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Configure core module settings such as labels, submission handling, and reCAPTCHA keys. ```javascript { label: 'aposForm:form', pluralLabel: 'aposForm:forms', quickCreate: true, seoFields: false, openGraph: false, i18n: { ns: 'aposForm', browser: true }, shortcut: 'G,O' } ``` -------------------------------- ### Initialize Submissions Collection Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Asynchronously initializes the 'aposFormSubmissions' collection and sets up database indexes for efficient querying. ```javascript async ensureCollection() ``` -------------------------------- ### Throwing a Field-Level Error Source: https://github.com/apostrophecms/form/blob/main/_autodocs/errors.md Example of how to programmatically throw a field-level error within the form submission process. This is typically done when validation rules are not met. ```javascript throw self.apos.error('invalid', { fieldError: { field: widget.fieldName, error: 'required', message: req.t('aposForm:requiredError') } }); ``` -------------------------------- ### Form Divider Widget Configuration Source: https://github.com/apostrophecms/form/blob/main/modules/@apostrophecms/form-divider-widget/views/widget.html Sets up the widget's class name, prioritizing widget-specific options over manager options. ```html {% set prependIfPrefix = apos.modules['@apostrophecms/form'].prependIfPrefix %} {% set className = '' %} {% if data.options.className %} {% set className = data.options.className %} {% elif data.manager.options.className %} {% set className = data.manager.options.className %} {% endif %} ``` -------------------------------- ### Get Widget Manager Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Retrieves the widget manager for a given field widget type. This is used to access methods for sanitizing and validating field values. ```javascript const manager = self.apos.area.getWidgetManager(widget.type); ``` -------------------------------- ### Default thankYouWidgets Configuration Source: https://github.com/apostrophecms/form/blob/main/_autodocs/configuration.md The default configuration for thankYouWidgets includes only the rich text editor. ```javascript { '@apostrophecms/rich-text': { toolbar: [ 'styles', 'bold', 'italic', 'link', 'orderedList', 'bulletList' ] } } ``` -------------------------------- ### Custom Validator Error Throwing Source: https://github.com/apostrophecms/form/blob/main/_autodocs/errors.md This example demonstrates how a downstream handler can throw a custom error during form submission processing. The error is caught and returned in the API response. ```javascript handlers(self) { return { submission: { async customValidator(req, form, data) { if (!data.email || !data.email.includes('@')) { throw self.apos.error('invalid', { fieldError: { field: 'email', error: 'invalid', message: 'Invalid email format' } }); } } } }; } ``` -------------------------------- ### Capture URL Parameters Configuration Source: https://github.com/apostrophecms/form/blob/main/_autodocs/README.md Enable the capture of URL parameters for form submissions by setting 'enableQueryParams' to true and defining the parameters to capture in 'queryParamList'. Each parameter can have a key and an optional length limit. ```javascript { enableQueryParams: true, queryParamList: [ { key: 'source', lengthLimit: 50 }, { key: 'campaign', lengthLimit: 100 } ] } ``` -------------------------------- ### Configure Email Submission Conditions Source: https://github.com/apostrophecms/form/blob/main/_autodocs/configuration.md Set up complex field value matching for email submission rules using CSV parsing. Values can be quoted to include commas. ```javascript { email: 'specialist@example.com', conditions: [ { field: 'issueType', value: '"Issue A", "Issue B", "Issue with comma, inside"' } ] } ``` -------------------------------- ### Configure reCAPTCHA Site Key Source: https://github.com/apostrophecms/form/blob/main/_autodocs/configuration.md Provide the client-side public key for Google reCAPTCHA v3. This module-level configuration takes precedence over global settings. ```javascript { recaptchaSite: 'your-site-key-from-google' } ``` -------------------------------- ### Custom Score-Based reCAPTCHA Validation Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/recaptcha.md Example of a custom submission handler that implements score-based reCAPTCHA validation. It throws an 'invalid' error if the reCAPTCHA score is below 0.5, indicating suspected bot activity. ```javascript handlers(self) { return { submission: { async scoreBasedValidation(req, form, data) { if (form.enableRecaptcha && data.recaptchaScore < 0.5) { throw self.apos.error('invalid', { fieldError: { global: true, error: 'recaptcha', message: 'Suspected bot activity' } }); } } } }; } ``` -------------------------------- ### Form Module Options Configuration Source: https://github.com/apostrophecms/form/blob/main/_autodocs/types.md The configuration object for the form module. Allows customization of labels, creation options, SEO and OpenGraph fields, email settings, reCAPTCHA keys, CSS prefixes, and widget configurations. ```javascript { label: string, pluralLabel: string, quickCreate: boolean, seoFields: boolean, openGraph: boolean, i18n: { ns: string, browser: boolean }, shortcut: string, emailSubmissions: boolean, saveSubmissions: boolean, recaptchaSecret: string, recaptchaSite: string, classPrefix: string, formWidgets: object, thankYouWidgets: object, testing: boolean } ``` -------------------------------- ### insertFieldFiles(req, name, files) Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Asynchronously processes and inserts uploaded files as attachments, matching them by field name. Returns an array of attachment IDs. ```APIDOC ## insertFieldFiles(req, name, files) ### Description Process and insert uploaded files as attachments. Finds all uploaded files matching the field name, inserts each as an attachment, and returns an array of attachment IDs. Files are stored without permission restrictions. ### Parameters #### Path Parameters * None #### Query Parameters * None #### Request Body * None ### Method * `async` Function ### Endpoint * N/A ### Returns * `Promise>` — Array of attachment IDs ``` -------------------------------- ### Configure Query Parameter Validation Source: https://github.com/apostrophecms/form/blob/main/_autodocs/configuration.md Enable query parameter capture and define an allowlist with optional length limits. Parameters are URL-decoded and truncated. ```javascript { enableQueryParams: true, queryParamList: [ { key: 'source', lengthLimit: 50 }, { key: 'campaign', lengthLimit: 100 }, { key: 'utm_source' } // No limit ] } ``` -------------------------------- ### Usage of Testing Mode in Tests Source: https://github.com/apostrophecms/form/blob/main/_autodocs/configuration.md Demonstrates how to use the testing mode in your tests. The `sendEmailSubmissions` method will return an array of recipients instead of sending emails. ```javascript const recipients = await self.sendEmailSubmissions(req, form, data); // returns: ['admin@example.com', 'sales@example.com'] // instead of actually sending emails ``` -------------------------------- ### JavaScript Fetch Request to Submit Form Source: https://github.com/apostrophecms/form/blob/main/_autodocs/endpoints.md This snippet demonstrates how to construct and send a form submission using the Fetch API in JavaScript. It includes building FormData, adding reCAPTCHA tokens, query parameters, and file uploads. ```javascript async function submitForm(formElement) { const formData = new FormData(); // Build submission object const submissionData = { _id: formElement.dataset.formId, fieldName: formElement.querySelector('input[name="fieldName"]').value }; // Add reCAPTCHA token if needed if (window.grecaptcha) { submissionData.recaptcha = await grecaptcha.execute(); } // Add query parameters if needed const urlParams = new URLSearchParams(window.location.search); if (urlParams.has('source')) { submissionData.queryParams = { source: urlParams.get('source') }; } formData.append('data', JSON.stringify(submissionData)); // Add file inputs const fileInputs = formElement.querySelectorAll('input[type="file"]'); for (const input of fileInputs) { for (const file of input.files) { formData.append(`${input.name}-${i++}`, file); } } // Submit const response = await fetch('/api/v1/@apostrophecms/form/submit', { method: 'POST', body: formData }); const result = await response.json(); if (response.ok) { console.log('Form submitted successfully'); } else { console.log('Validation errors:', result.formErrors); } return result; } ``` -------------------------------- ### Query Parameter Configuration Structure Source: https://github.com/apostrophecms/form/blob/main/_autodocs/types.md Defines how URL query parameters are captured and stored, including their name and an optional length limit. ```javascript { key: string, lengthLimit: integer } ``` -------------------------------- ### Enable reCAPTCHA Configuration Source: https://github.com/apostrophecms/form/blob/main/_autodocs/README.md Configure reCAPTCHA for your forms by providing the secret and site keys in the module configuration. This requires client-side integration as well. ```javascript { '@apostrophecms/form': { recaptchaSecret: process.env.RECAPTCHA_SECRET, recaptchaSite: process.env.RECAPTCHA_SITE } } ``` -------------------------------- ### Query Parameter Capture Configuration Source: https://github.com/apostrophecms/form/blob/main/_autodocs/endpoints.md Configure the form to capture specific URL query parameters. These parameters are then included in the submission data. ```javascript { title: 'Newsletter Signup', enableQueryParams: true, queryParamList: [ { key: 'source', lengthLimit: 50 }, { key: 'campaign', lengthLimit: 100 } ] } ``` -------------------------------- ### Configure Form Module with reCAPTCHA Source: https://github.com/apostrophecms/form/blob/main/_autodocs/README.md Launch ApostropheCMS with the form module configured for reCAPTCHA, enabling email and database submissions. ```javascript const apos = require('apostrophe'); apos.launch({ modules: { '@apostrophecms/form': { recaptchaSecret: 'your-secret-key', recaptchaSite: 'your-site-key', emailSubmissions: true, saveSubmissions: true } } }); ``` -------------------------------- ### ensureCollection() Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Initialize the submissions collection and indexes. This asynchronous method creates the `aposFormSubmissions` collection and establishes necessary database indexes for efficient querying. ```APIDOC ## ensureCollection() ### Description Initialize the submissions collection and indexes. This asynchronous method creates the `aposFormSubmissions` collection and establishes necessary database indexes for efficient querying. ### Signature ```javascript async ensureCollection() ``` ### Returns `Promise` ``` -------------------------------- ### File Handling Methods Source: https://github.com/apostrophecms/form/blob/main/_autodocs/README.md Methods for processing file uploads within form submissions. ```APIDOC ### File Handling - **`insertFieldFiles(req, name, files)`** - Description: Process and insert uploaded files associated with a form field. - **`normalizeFiles(req, res, next)`** - Description: Express middleware to normalize file uploads before processing. ``` -------------------------------- ### Insert Uploaded Files as Attachments Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Asynchronously processes and inserts uploaded files matching a given field name as attachments. Returns an array of attachment IDs. Files are stored without permission restrictions. ```javascript async insertFieldFiles(req, name, files) ``` -------------------------------- ### File Processing Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/submission-handling.md File fields are processed specially. Client-side, they are marked as 'files-pending'. The server then handles the insertion of these files, returning an array of their IDs. ```APIDOC ## File Processing File fields are handled specially. On the client, the field value is set to `'files-pending'`. The server processes these: ### File Insertion **Method:** `insertFieldFiles(req, name, files)` Files are matched by name pattern and inserted without permission restrictions. ### File Name Matching **Method:** `matchesName(str, name)` Matches files named like `fieldName-1`, `fieldName-2`, etc., to support multiple file uploads per field. ``` -------------------------------- ### Insert Field Files Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/submission-handling.md This asynchronous method handles the insertion of uploaded files into the ApostropheCMS attachment storage. It iterates through provided files, matches them against a given field name pattern, inserts them as attachments, and returns an array of their IDs. ```javascript async insertFieldFiles (req, name, files) { const ids = []; for (const entry in files) { if (!self.matchesName(entry, name)) { continue; } const attachment = await self.apos.attachment.insert(req, files[entry], { permissions: false }); ids.push(attachment._id); } return ids; } ``` -------------------------------- ### Discover Form Fields and Track Conditionals Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/submission-handling.md Walks through the form's content areas to discover all fields and track conditional widgets. This allows for complex nested form structures while maintaining flat submission data. ```javascript const areas = []; const fieldNames = []; const conditionals = {}; self.apos.area.walk({ contents: form.contents }, function(area) { areas.push(area); }); for (const area of areas) { const widgets = area.items || []; for (const widget of widgets) { fieldNames.push(widget.fieldName); if (widget.type === '@apostrophecms/form-conditional') { self.trackConditionals(conditionals, widget); } } } ``` -------------------------------- ### Send Email with Named Template Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Sends an email using a specified template and configuration options. Useful for sending confirmation or notification emails. The 'from', 'to', 'subject', 'form', and 'data' can be customized. ```javascript await self.sendEmail(req, 'emailConfirmation', { form: formDocument, data: submissionData, from: 'noreply@example.com', to: 'user@example.com', subject: 'Thank you for your submission' }); ``` -------------------------------- ### getRecaptchaSecret(req, self) Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Asynchronously retrieves the reCAPTCHA secret key, checking module options first and then global settings. Returns null if the key is not configured in either location. ```APIDOC ## getRecaptchaSecret(req, self) ### Description Retrieve reCAPTCHA secret key from options or global settings. Returns the reCAPTCHA secret from module options, falling back to global settings if available. Returns null if neither source has the key configured. ### Parameters #### Path Parameters * None #### Query Parameters * None #### Request Body * None ### Method * `async` Function ### Endpoint * N/A ### Returns * `Promise` — Secret key or null if not configured ``` -------------------------------- ### Not Found Response Source: https://github.com/apostrophecms/form/blob/main/_autodocs/endpoints.md Returned with a 404 status if the form ID specified in the submission request does not exist. ```json { "error": "notfound" } ``` -------------------------------- ### Conditional Logic Methods Source: https://github.com/apostrophecms/form/blob/main/_autodocs/README.md Methods for managing conditional visibility of form fields. ```APIDOC ### Conditionals - **`trackConditionals(conditionals, widget)`** - Description: Map field visibility rules based on conditional settings. - **`collectToSkip(input, conditionals, skipFields)`** - Description: Identify fields that should be skipped based on conditional logic. ``` -------------------------------- ### Client-Side Fetch and Error Handling Source: https://github.com/apostrophecms/form/blob/main/_autodocs/errors.md This client-side code demonstrates how to fetch form submission results and handle potential errors returned in the response, including 'notfound' and 'invalid' error types. ```javascript const response = await fetch('/api/v1/@apostrophecms/form/submit', { method: 'POST', body: formData }); const result = await response.json(); if (!response.ok) { // Handle errors if (result.error === 'notfound') { // Form not found } else if (result.error === 'invalid') { // Process formErrors array result.formErrors.forEach(err => { if (err.global) { // Global error } else { // Field-level error } }); } } ``` -------------------------------- ### Check Input Macro Source: https://github.com/apostrophecms/form/blob/main/modules/@apostrophecms/form-base-field-widget/views/fragments/utility.html A placeholder macro for checking input related to form fields. It retrieves a prefixer function from the form module's options. ```html {% macro checkInput(widget, choice, id) %} {% set prefixer = apos.modules\[\'@apostrophecms/form\'\]\.prependIfPrefix %} {% endmacro %} ``` -------------------------------- ### Handling reCAPTCHA Configuration Errors Source: https://github.com/apostrophecms/form/blob/main/_autodocs/errors.md This snippet illustrates how to detect and handle reCAPTCHA configuration errors on the client-side. It suggests showing a user-friendly message indicating temporary unavailability. ```javascript if (response.error === 'recaptcha' && response.formErrors[0].message.includes('configuration')) { console.error('Server reCAPTCHA configuration issue'); // Show user-friendly message showError('Form submission is temporarily unavailable'); } ``` -------------------------------- ### Success Response Source: https://github.com/apostrophecms/form/blob/main/_autodocs/endpoints.md An empty object is returned on successful form submission, indicating the data was processed without errors. ```json {} ``` -------------------------------- ### Register Submission Event Handler Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/submission-handling.md This demonstrates how to register a custom handler for the 'submission' event. The handler receives the request, form, and submission data, enabling custom processing logic after a successful form submission. ```javascript handlers(self) { return { submission: { async myCustomHandler(req, form, data) { // Process submission data } } }; } ``` -------------------------------- ### getRecaptchaSecret Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/recaptcha.md Retrieves the reCAPTCHA secret key, checking module options first and then global settings. Returns the secret key as a string or null if not configured. ```APIDOC ## getRecaptchaSecret(req, self) ### Description Retrieve the reCAPTCHA secret key from module configuration or global settings. ### Method Signature ```javascript async getRecaptchaSecret(req, self) ``` ### Parameters #### Parameters - **req** (Express.Request) - Request object for context - **self** (object) - Module context (the form module instance) ### Returns `Promise` — Secret key if configured, null otherwise ### Description Resolves reCAPTCHA configuration in priority order: 1. Returns `self.options.recaptchaSecret` if set in module options 2. Falls back to `globalDoc.recaptchaSecret` if global settings enabled 3. Returns null if no configuration found ### Example ```javascript const secret = await self.getRecaptchaSecret(req, self); if (secret) { // reCAPTCHA is enabled and configured } ``` ``` -------------------------------- ### Configure reCAPTCHA Secret Key Source: https://github.com/apostrophecms/form/blob/main/_autodocs/configuration.md Provide the server-side secret key for Google reCAPTCHA v3 verification. This module-level configuration takes precedence over global settings. ```javascript { recaptchaSecret: 'your-secret-key-from-google' } ``` -------------------------------- ### reCAPTCHA Configuration Error Response Source: https://github.com/apostrophecms/form/blob/main/_autodocs/endpoints.md Illustrates error responses when reCAPTCHA is enabled but a server-side configuration issue prevents validation. ```json { "error": "invalid", "formErrors": [ { "global": true, "error": "recaptcha", "message": "reCAPTCHA configuration error" } ] } ``` -------------------------------- ### Email Sending Options Object Source: https://github.com/apostrophecms/form/blob/main/_autodocs/configuration.md The options object for the `sendEmail` method includes details about the form, submission data, sender, recipient, and subject. ```javascript { form: formDocument, data: submissionData, from: 'sender@example.com', // Optional; defaults to form.email to: 'recipient@example.com', // Required subject: 'Email Subject' // Optional; defaults to form.title } ``` -------------------------------- ### Configure Localization Namespace Source: https://github.com/apostrophecms/form/blob/main/_autodocs/configuration.md Set the localization namespace to 'aposForm' for all localized strings used by the form module. This enables browser-side localization. ```javascript { i18n: { ns: 'aposForm', browser: true } } ``` -------------------------------- ### Global Error Response Format (Form Not Found) Source: https://github.com/apostrophecms/form/blob/main/_autodocs/errors.md Standardized format for reporting a global submission error when the specified form cannot be found. This error typically results in a 404 HTTP status. ```javascript { error: "notfound" } ``` -------------------------------- ### File Object Format Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Defines the structure of a file object after normalization by `normalizeFiles`. ```javascript { path: string, // Temporary file path name: string, // Original filename type: string, // MIME type size: number // File size in bytes } ``` -------------------------------- ### POST /api/v1/@apostrophecms/form/submit Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Submit form data for processing and storage. This endpoint accepts multipart/form-data, parses it, and then processes the submission using the 'submitForm' middleware. ```APIDOC ## POST /api/v1/@apostrophecms/form/submit ### Description Submit form data for processing and storage. This endpoint accepts multipart/form-data, parses it, and then processes the submission using the 'submitForm' middleware. ### Method POST ### Endpoint /api/v1/@apostrophecms/form/submit ### Parameters #### Request Body - **data** (string) - Required - JSON stringified form data object. ### Request Example ```json { "data": "{\"_id\": \"formId\", \"fieldName\": \"fieldValue\", \"recaptcha\": \"token\", \"queryParams\": {}}" } ``` ### Response #### Success Response (200) An empty object `{}` is returned upon successful submission. #### Error Response Format ```json { "error": "string", "formErrors": [ { "field": "string", "error": "string", "message": "string" } ] } ``` - Status 400: `{ error: "invalid", formErrors: [] }` - Status 404: `{ error: "notfound" }` ``` -------------------------------- ### Database Index for Submissions (Ascending) Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Defines the first database index on the 'aposFormSubmissions' collection, enabling efficient querying of submissions ordered by form ID and then creation date in ascending order. ```javascript { formId: 1, createdAt: 1 } ``` -------------------------------- ### Divider Widget Configuration Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/field-widgets.md Shows the default configuration for the divider widget, which is used for visual separation in forms. This widget does not affect form data. ```javascript { label: 'aposForm:divider', initialModal: false, className: 'apos-form-divider', icon: 'minus-icon' } ``` -------------------------------- ### Field Widget Structure Source: https://github.com/apostrophecms/form/blob/main/_autodocs/types.md Extends the base widget structure with properties specific to form input fields. ```javascript { type: '@apostrophecms/form-*-field-widget', _id: string, fieldName: string, fieldLabel: string, required: boolean, classPrefix: string, // Type-specific fields: inputType: string, // Text field placeholder: string, // Text/textarea/select fields choices: array, // Select/radio/checkboxes fields allowMultiple: boolean, // Select/file fields size: integer, // Select field checked: boolean, // Boolean field limitSize: boolean, // File field maxSize: integer // File field } ``` -------------------------------- ### Query Parameters Object Schema Source: https://github.com/apostrophecms/form/blob/main/_autodocs/endpoints.md Defines the structure for the optional query parameters object, where each parameter is captured as a string value. ```javascript { paramKey: string, } ``` -------------------------------- ### checkRecaptcha(req, input, formErrors) Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Asynchronously validates the reCAPTCHA token submitted with the form by calling Google's verification endpoint. Errors are appended to the `formErrors` array if validation fails or is not configured. ```APIDOC ## checkRecaptcha(req, input, formErrors) ### Description Validate reCAPTCHA token submitted with the form. Validates the reCAPTCHA token by calling Google's verification endpoint. If validation fails or is not configured, appends an error object to formErrors. Does not throw; errors are collected for return to client. ### Parameters #### Path Parameters * None #### Query Parameters * None #### Request Body * None ### Method * `async` Function ### Endpoint * N/A ### Returns * `Promise` — Modifies formErrors array in place ### Appended Error Object (if validation fails) ```javascript { global: true, error: 'recaptcha', message: string // Localized error message } ``` ``` -------------------------------- ### cleanOptions Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/recaptcha.md Validates and cleans reCAPTCHA configuration options, ensuring both secret and site keys are present. Modifies the options object in place. ```APIDOC ## cleanOptions(options) ### Description Validate and clean reCAPTCHA configuration options. ### Method Signature ```javascript cleanOptions(options) ``` ### Parameters #### Parameters - **options** (object) - Module options object ### Returns `undefined` — Modifies options object in place ### Description Ensures that reCAPTCHA is only enabled if both the secret key and site key are provided. If either is missing, both are deleted to prevent partial configuration. ### Logic ```javascript if (!options.recaptchaSecret || !options.recaptchaSite) { delete options.recaptchaSite; delete options.recaptchaSecret; } ``` ### Called During module initialization in `init()` hook ### Example ```javascript // Configuration with both keys - valid const opts1 = { recaptchaSecret: 'secret-key', recaptchaSite: 'site-key' }; self.cleanOptions(opts1); // Result: both keys remain // Configuration with only secret - invalid const opts2 = { recaptchaSecret: 'secret-key' }; self.cleanOptions(opts2); // Result: recaptchaSecret is deleted, no reCAPTCHA ``` ``` -------------------------------- ### Conditional Global Settings Logic Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/recaptcha.md This JavaScript snippet demonstrates the condition under which reCAPTCHA configuration fields are added to the global document. It checks if module-level configuration is absent. ```javascript if (!formOptions.recaptchaSecret && !formOptions.recaptchaSite) { // Form module doesn't have module-level reCAPTCHA config // Add global settings fields } ``` -------------------------------- ### reCAPTCHA Submission Error Response Source: https://github.com/apostrophecms/form/blob/main/_autodocs/endpoints.md Illustrates error responses when reCAPTCHA is enabled but no token is provided during submission. ```json { "error": "invalid", "formErrors": [ { "global": true, "error": "recaptcha", "message": "reCAPTCHA submission error" } ] } ``` -------------------------------- ### Retrieve Form Document by ID Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/submission-handling.md Retrieves the form document from the database using its ID. Throws a 'notfound' error if the form does not exist. Handles page context and locale resolution. ```javascript const formId = self.inferIdLocaleAndMode(req, input._id); const form = await self.find(req, { _id: self.apos.launder.id(formId) }).toObject(); if (!form) { throw self.apos.error('notfound'); } ``` -------------------------------- ### Container Widget Structure Source: https://github.com/apostrophecms/form/blob/main/_autodocs/types.md Defines the structure for container widgets like conditional fields or groups, extending the base widget properties. ```javascript { type: '@apostrophecms/form-conditional-widget' | '@apostrophecms/form-group-widget', _id: string, label: string, // Group widget conditionName: string, // Conditional widget conditionValue: string, // Conditional widget contents: area } ``` -------------------------------- ### trackConditionals(conditionals, widget) Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Tracks field visibility dependencies for conditional widgets by populating a conditionals object with field visibility rules. Maps condition names and values to arrays of field names that should be visible when that condition is met. ```APIDOC ## trackConditionals(conditionals, widget) ### Description Track field visibility dependencies for conditional widgets. Populates the conditionals object with field visibility rules. Maps condition names and values to arrays of field names that should be visible when that condition is met. ### Parameters #### Path Parameters * None #### Query Parameters * None #### Request Body * None ### Method * Function ### Endpoint * N/A ### Returns * `undefined` — Modifies conditionals object in place ### Conditionals Structure ```javascript { fieldName: { value1: ['field1', 'field2'], value2: ['field3', 'field4'] } } ``` ``` -------------------------------- ### Form Document Schema Source: https://github.com/apostrophecms/form/blob/main/_autodocs/types.md Defines the structure of a form piece document, including its fields and submission handling configuration. ```javascript { _id: ObjectId, type: '@apostrophecms/form', slug: string, title: string, contents: area, submitLabel: string, thankYouHeading: string, thankYouBody: area, sendConfirmationEmail: boolean, emailConfirmationField: string, enableRecaptcha: boolean, enableQueryParams: boolean, queryParamList: array, emails: array, email: string, createdAt: Date, updatedAt: Date, // ... additional piece-type fields } ``` -------------------------------- ### Extract and Tidy Query Parameters Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/submission-handling.md This method extracts specified query parameters from the input, validates them against an allowlist, skips parameters that match existing form field names, cleans them using `tidyParamValue`, and adds them to the output object. ```javascript processQueryParams(form, input, output, fieldNames) { if (!input.queryParams || (typeof input.queryParams !== 'object')) { output.queryParams = null; return; } if (Array.isArray(form.queryParamList) && form.queryParamList.length > 0) { form.queryParamList.forEach(param => { if (fieldNames.includes(param.key)) { return; // Skip if matches existing field } const value = input.queryParams[param.key]; if (value) { output[param.key] = self.tidyParamValue(param, value); } else { output[param.key] = null; } }); } } ``` -------------------------------- ### collectToSkip(input, conditionals, skipFields) Source: https://github.com/apostrophecms/form/blob/main/_autodocs/api-reference/form-module.md Determine which fields should be excluded from processing based on unmet conditions. This method iterates through conditionals and adds fields to `skipFields` if their visibility conditions are not met. ```APIDOC ## collectToSkip(input, conditionals, skipFields) ### Description Determine which fields should be excluded from processing based on unmet conditions. This method iterates through conditionals and adds fields to `skipFields` if their visibility conditions are not met. ### Signature ```javascript collectToSkip(input, conditionals, skipFields) ``` ### Parameters #### Path Parameters - **input** (object) - Required - Form submission data. - **conditionals** (object) - Required - Conditional field tracking object. - **skipFields** (array) - Required - Array to append field names to. ### Returns `undefined` — Modifies skipFields array in place. ```