(function() { 'use strict'; window.utils = window.utils || {}; var formUtilities = []; var JS_INITIALIZED = 'js-form-initialized'; var AUTOSUBMIT_BUTTON_SELECTOR = '[type="submit"][data-autosubmit]'; var AJAX_SUBMIT_FLAG = 'ajaxSubmit'; var FORM_GROUP_CLASS = 'form-group'; var FORM_GROUP_WITH_ERRORS_CLASS = 'form-group--has-error'; window.utils.form = function(form, options) { options = options || {}; // dont initialize form if it is in a modal and is not forced if (form.closest('.modal') && !options.force) { return false; } // dont initialize form if already initialized and should not be force-initialized if (form.classList.contains(JS_INITIALIZED) && !options.force) { return false; } var utilInstances = []; // reactive buttons utilInstances.push(window.utils.setup('reactiveButton', form)); // conditonal fieldsets var fieldSets = Array.from(form.querySelectorAll('fieldset[data-conditional-id][data-conditional-value]')); utilInstances.push(window.utils.setup('interactiveFieldset', form, { fieldSets })); // hide autoSubmit submit button utilInstances.push(window.utils.setup('autoSubmit', form, options)); // async form if (AJAX_SUBMIT_FLAG in form.dataset) { utilInstances.push(window.utils.setup('asyncForm', form, options)); } // inputs utilInstances.push(window.utils.setup('inputs', form, options)); // form group errors var formGroups = Array.from(form.querySelectorAll('.' + FORM_GROUP_CLASS)); formGroups.forEach(function(formGroup) { utilInstances.push(window.utils.setup('errorRemover', formGroup, options)); }); form.classList.add(JS_INITIALIZED); function destroyUtils() { utilInstances.filter(function(utilInstance) { return !!utilInstance; }).forEach(function(utilInstance) { utilInstance.destroy(); }); } return { scope: form, destroy: destroyUtils, }; }; /** * * Reactive Submit Button Utility * disables a forms LAST sumit button as long as the required inputs are invalid * (only checks if the value of the inputs are not empty) * * Attribute: [none] * (automatically setup on all form tags) * * Params: * data-formnorequired: string * If present the submit button will never get disabled * * Example usage: *
*/ var REACTIVE_SUBMIT_BUTTON_UTIL_NAME = 'reactiveSubmitButton'; var REACTIVE_SUBMIT_BUTTON_UTIL_SELECTOR = 'form'; var REACTIVE_SUBMIT_BUTTON_INITIALIZED_CLASS = 'reactive-submit-button--initialized'; var reactiveButtonUtil = function(element) { var requiredInputs; var submitButton; function init() { if (!element) { throw new Error('Reactive Submit Button utility cannot be setup without an element!'); } if (element.classList.contains(REACTIVE_SUBMIT_BUTTON_INITIALIZED_CLASS)) { throw new Error('Reactive Submit Button utility already initialized!'); } // abort if form has param data-formnorequired if (element.dataset.formnorequired !== undefined) { throw new Error('Form has formnorequired data attribute. Will skip setup of reactive submit button.'); } requiredInputs = Array.from(element.querySelectorAll('[required]')); if (!requiredInputs) { // abort if form has no required inputs throw new Error('Submit button has formnorequired data attribute. Will skip setup of reactive submit button.'); } var submitButtons = Array.from(element.querySelectorAll('[type="submit"]')); if (!submitButtons) { throw new Error('Reactive Submit Button utility couldn\'t find any submit buttons!'); } submitButton = submitButtons.reverse()[0]; // abort if form has param data-formnorequired if (submitButton.dataset.formnorequired !== undefined) { return false; } setupInputs(); updateButtonState(); element.classList.add(REACTIVE_SUBMIT_BUTTON_INITIALIZED_CLASS); return { name: REACTIVE_SUBMIT_BUTTON_UTIL_NAME, element: element, destroy: function() {}, }; } function setupInputs() { requiredInputs.forEach(function(el) { var checkbox = el.getAttribute('type') === 'checkbox'; var eventType = checkbox ? 'change' : 'input'; el.addEventListener(eventType, function() { updateButtonState(); }); }); } function updateButtonState() { if (inputsValid()) { submitButton.removeAttribute('disabled'); } else { console.log('setting disabled', { submitButton }); submitButton.setAttribute('disabled', 'true'); } } function inputsValid() { var done = true; requiredInputs.forEach(function(inp) { var len = inp.value.trim().length; if (done && len === 0) { done = false; } }); return done; } return init(); }; formUtilities.push({ name: REACTIVE_SUBMIT_BUTTON_UTIL_NAME, selector: REACTIVE_SUBMIT_BUTTON_UTIL_SELECTOR, setup: reactiveButtonUtil, }); window.utils.interactiveFieldset = function(form, options) { options = options || {}; var fieldSets = options.fieldSets; if (!fieldSets) { throw new Error('interactiveFieldset must be passed fieldSets via options'); } var fields = fieldSets.map(function(fs) { return { fieldSet: fs, condId: fs.dataset.conditionalId, condValue: fs.dataset.conditionalValue, condEl: form.querySelector('#' + fs.dataset.conditionalId), }; }).filter(function(field) { return !!field.condEl; }); function updateFields() { fields.forEach(function(field) { field.fieldSet.classList.toggle('hidden', field.condEl.value !== field.condValue); }); } function addEventListeners() { fields.forEach(function(field) { field.condEl.addEventListener('input', updateFields) }); } if (fieldSets.length) { addEventListeners(); updateFields(); } return { scope: form, destroy: function() {}, }; }; window.utils.autoSubmit = function(form, options) { var button = form.querySelector(AUTOSUBMIT_BUTTON_SELECTOR); if (button) { button.classList.add('hidden'); } return { scope: form, destroy: function() {}, }; }; // listens for focus events and removes any errors on an input window.utils.errorRemover = function(formGroup, options) { var inputElement = formGroup.querySelector('input:not([type="hidden"]), textarea, select'); if (!inputElement) { return false; } inputElement.addEventListener('focus', focusListener); function focusListener() { var hasError = formGroup.classList.contains(FORM_GROUP_WITH_ERRORS_CLASS); if (hasError) { formGroup.classList.remove(FORM_GROUP_WITH_ERRORS_CLASS); } } return { scope: formGroup, destroy: function() { inputElement.removeEventListener('focus', focusListener); }, }; }; // register the collected form utilities if (UtilRegistry) { formUtilities.forEach(UtilRegistry.register); } })();