diff options
Diffstat (limited to 'app/assets/javascripts/lib/utils/forms.js')
-rw-r--r-- | app/assets/javascripts/lib/utils/forms.js | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/app/assets/javascripts/lib/utils/forms.js b/app/assets/javascripts/lib/utils/forms.js index 52e1323412d..b58aef15dda 100644 --- a/app/assets/javascripts/lib/utils/forms.js +++ b/app/assets/javascripts/lib/utils/forms.js @@ -1,3 +1,5 @@ +import { convertToCamelCase } from '~/lib/utils/text_utility'; + export const serializeFormEntries = (entries) => entries.reduce((acc, { name, value }) => Object.assign(acc, { [name]: value }), {}); @@ -51,3 +53,95 @@ export const serializeFormObject = (form) => return acc; }, []), ); + +/** + * Parse inputs of HTML forms generated by Rails. + * + * This can be helpful when mounting Vue components within Rails forms. + * + * If called with an HTML element like: + * + * ```html + * <input type="text" placeholder="Email" value="foo@bar.com" name="user[contact_info][email]" id="user_contact_info_email" data-js-name="contactInfoEmail"> + * <input type="text" placeholder="Phone" value="(123) 456-7890" name="user[contact_info][phone]" id="user_contact_info_phone" data-js-name="contactInfoPhone"> + * <input type="checkbox" name="user[interests][]" id="user_interests_vue" value="Vue" checked data-js-name="interests"> + * <input type="checkbox" name="user[interests][]" id="user_interests_graphql" value="GraphQL" data-js-name="interests"> + * ``` + * + * It will return an object like: + * + * ```javascript + * { + * contactInfoEmail: { + * name: 'user[contact_info][email]', + * id: 'user_contact_info_email', + * value: 'foo@bar.com', + * placeholder: 'Email', + * }, + * contactInfoPhone: { + * name: 'user[contact_info][phone]', + * id: 'user_contact_info_phone', + * value: '(123) 456-7890', + * placeholder: 'Phone', + * }, + * interests: [ + * { + * name: 'user[interests][]', + * id: 'user_interests_vue', + * value: 'Vue', + * checked: true, + * }, + * { + * name: 'user[interests][]', + * id: 'user_interests_graphql', + * value: 'GraphQL', + * checked: false, + * }, + * ], + * } + * ``` + * + * @param {HTMLInputElement} mountEl + * @returns {Object} object with form fields data. + */ +export const parseRailsFormFields = (mountEl) => { + if (!mountEl) { + throw new TypeError('`mountEl` argument is required'); + } + + const inputs = mountEl.querySelectorAll('[name]'); + + return [...inputs].reduce((accumulator, input) => { + const fieldName = input.dataset.jsName; + + if (!fieldName) { + return accumulator; + } + + const fieldNameCamelCase = convertToCamelCase(fieldName); + const { id, placeholder, name, value, type, checked } = input; + const attributes = { + name, + id, + value, + ...(placeholder && { placeholder }), + }; + + // Store radio buttons and checkboxes as an array so they can be + // looped through and rendered in Vue + if (['radio', 'checkbox'].includes(type)) { + return { + ...accumulator, + [fieldNameCamelCase]: [ + ...(accumulator[fieldNameCamelCase] || []), + { ...attributes, checked }, + ], + }; + } + + return { + ...accumulator, + [fieldNameCamelCase]: attributes, + }; + }, {}); +}; |