UNPKG

@modular-forms/react

Version:

The modular and type-safe form library for React

101 lines (100 loc) 4.39 kB
import { batch } from '@preact/signals-react'; import { getFilteredNames, getOptions, getUniqueId, getFieldStore, getFieldArrayStore, setErrorResponse, updateFormInvalid, } from '../utils'; import { focus } from './focus'; import { getValues } from './getValues'; export async function validate(form, arg2, arg3) { // Filter names between field and field arrays const [fieldNames, fieldArrayNames] = getFilteredNames(form, arg2); // Destructure options and set default values const { shouldActive = true, shouldFocus = true } = getOptions(arg2, arg3); // Create unique validator ID and add it to list const validator = getUniqueId(); form.internal.validators.add(validator); // Set validating to "true" form.validating.value = true; // Run form validation function const formErrors = form.internal.validate ? await form.internal.validate(getValues(form, { shouldActive, peek: true })) : {}; // Create valid variable let valid = typeof arg2 !== 'string' && !Array.isArray(arg2) ? !Object.keys(formErrors).length : true; const [errorFields] = await Promise.all([ // Validate each field in list Promise.all(fieldNames.map(async (name) => { // Get store of specified field const field = getFieldStore(form, name); // Continue if field corresponds to filter options if (!shouldActive || field.active.peek()) { // Create local error variable let localError; // Run each field validation functions for (const validation of field.validate) { localError = await validation(field.value.peek()); // Break loop if an error occurred if (localError) { break; } } // Create field error from local and global error const fieldError = localError || formErrors[name] || ''; // Set valid to "false" if an error occurred if (fieldError) { valid = false; } // Update error state of field field.error.value = fieldError; // Return name if field has an error return fieldError ? name : null; } })), // Validate each field array in list Promise.all(fieldArrayNames.map(async (name) => { // Get store of specified field array const fieldArray = getFieldArrayStore(form, name); // Continue if field array corresponds to filter options if (!shouldActive || fieldArray.active.peek()) { // Create local error variable let localError = ''; // Run each field array validation functions for (const validation of fieldArray.validate) { localError = await validation(fieldArray.items.peek()); // Break loop and if an error occurred if (localError) { break; } } // Create field array error from local and global error const fieldArrayError = localError || formErrors[name] || ''; // Set valid to "false" if an error occurred if (fieldArrayError) { valid = false; } // Update error state of field fieldArray.error.value = fieldArrayError; } })), ]); batch(() => { // Set error response if necessary setErrorResponse(form, formErrors, { shouldActive }); // Focus first field with an error if specified if (shouldFocus) { const name = errorFields.find((name) => name); if (name) { focus(form, name); } } // Update invalid state of form updateFormInvalid(form, !valid); // Delete validator from list form.internal.validators.delete(validator); // Set validating to "false" if there is no other validator if (!form.internal.validators.size) { form.validating.value = false; } }); // Return whether fields are valid return valid; }