UNPKG

@ngbrown/react-redux-form

Version:

Create Forms Easily with React and Redux

162 lines (127 loc) 4.19 kB
import actionTypes from '../../action-types'; import i from 'icepick'; import get from '../../utils/get'; import shallowEqual from '../../utils/shallow-equal'; import isPlainObject from '../../utils/is-plain-object'; import mapValues from '../../utils/map-values'; import { createInitialState } from '../form-reducer'; import initialFieldState from '../../constants/initial-field-state'; import assocIn from '../../utils/assoc-in'; import getFormValue from '../../utils/get-form-value'; import invariant from 'invariant'; function updateFieldValue(field, action, parentModel = undefined) { const { value, removeKeys, silent, load, model, external } = action; const fieldState = (field && field.$form) ? field.$form : field; const changedFieldProps = { validated: false, retouched: fieldState.submitted ? true : fieldState.retouched, // If change originated from Control component (not externally), // then there is no need to remind Control to validate itself. intents: external ? [{ type: 'validate' }] : [], pristine: silent ? fieldState.pristine : false, value, loadedValue: load ? value : fieldState.loadedValue, }; if (shallowEqual(field.value, value)) { return i.merge(field, changedFieldProps); } if (removeKeys) { invariant(field && field.$form, 'Unable to remove keys. ' + 'Field for "%s" in store is not an array/object.', model); const valueIsArray = Array.isArray(field.$form.value); const removeKeysArray = Array.isArray(removeKeys) ? removeKeys : [removeKeys]; let result; if (valueIsArray) { result = []; Object.keys(field).forEach((key) => { if (!!~removeKeysArray.indexOf(+key) || (key === '$form')) return; result[key] = { ...field[key] }; }); const finalResult = { ...result .filter((f) => f) .map((subField, index) => ({ ...subField, model: `${model}.${index}`, })), }; finalResult.$form = field.$form; return finalResult; } result = { ...field }; Object.keys(field).forEach((key) => { if (!!~removeKeysArray.indexOf(key)) { delete result[`${key}`]; } }); return result; } if (!Array.isArray(value) && !isPlainObject(value)) { return i.merge(field, i.set(changedFieldProps, 'value', value)); } const updatedField = mapValues(value, (subValue, index) => { // TODO: refactor const subField = field[index] || createInitialState(`${`${(parentModel ? `${parentModel}.` : '') }${model}`}.${index}`, subValue); if (Object.hasOwnProperty.call(subField, '$form')) { return updateFieldValue(subField, { model: index, value: subValue, external, silent, load, }, parentModel ? `${parentModel}.${model}` : model); } if (shallowEqual(subValue, subField.value)) { return subField; } return i.merge(subField, i.assign(changedFieldProps, { value: subValue, loadedValue: load ? subValue : subField.loadedValue, })); }); const dirtyFormState = i.merge(field.$form || initialFieldState, i.set(changedFieldProps, 'retouched', field.submitted || (field.$form && field.$form.retouched))); return i.set(updatedField, '$form', dirtyFormState); } export default function changeActionReducer(state, action, localPath) { if (action.type !== actionTypes.CHANGE) return state; const field = get(state, localPath, createInitialState(action.model, action.value)); const updatedField = updateFieldValue(field, action); if (!localPath.length) return updatedField; const updatedState = assocIn(state, localPath, updatedField, (form) => { if (!form.$form) return form; const formValue = getFormValue(form); const formUpdates = { ...form.$form, value: formValue, }; if (action.silent) { formUpdates.loadedValue = formValue; } else { formUpdates.pristine = false; } return { ...form, $form: formUpdates, }; }); return updatedState; }