src/actions.js
function fieldValidation (dispatch, getState, fieldValidators, formValue, initialFormValue, all) {
  let fieldsBeingValidated = []
  const allValidationPromises = []
  fieldValidators.forEach(validator => {
    /**
     * Field validator definition
     * @property {String} field field to validate
     * @property {String[]} fields fields to validate
     * @property {Function} validator validation function to validate field/fields. Must return field within error/warning
     * @property {Function[]} validators validation functions to validate field/fields. Must return field within error/warning
     */
    const {field, fields, validator: validatorFunc, validators: validatorFuncs} = validator

    const fieldsToValidate = fields || [field]
    fieldsBeingValidated = fieldsBeingValidated.concat(fieldsToValidate)
    fieldsToValidate.forEach((field) => {
      let fieldValidationPromises = []
      const newValue = _.get(formValue, field)
      const oldValue = _.get(initialFormValue, field)

      // Check if field value has changed
      if (!_.isEqual(newValue, oldValue) || !initialFormValue) {
        dispatchFieldIsValidating(dispatch, field, true)
        const validations = validatorFuncs || [validatorFunc]
            // Send validator formValue, the field we're validating against, and the field's value
        validations.forEach((validatorFunc, index) => {
          const fieldValidationPromise = validatorFunc(formValue, field, newValue)
            .then((result) => {
              const {
                fieldValidationResult: {
                  errors: currentErrors = [],
                  warnings: currentWarnings = []
                } = {}
              } = getState()
              const validationId = `${field}-${index}`
              const filterOutValidationId = (item) => item.validationId !== validationId
              const filteredOutErrors = currentErrors.filter(filterOutValidationId)
              const filteredOutWarnings = currentWarnings.filter(filterOutValidationId)

              // No need to use `aggregateResults as we should never have isRequired
              const {
                errors = [], warnings = []
              } = result.value
              const attachValidationId = (item) => {
                return _.assign({
                  validationId,
                  field
                }, item)
              }
              const newErrors = filteredOutErrors.concat(errors.map(attachValidationId))
              const errorsMappedToDotNotation = mapErrorsFromValidation(newErrors)

              dispatch({
                fieldErrors: errorsMappedToDotNotation,
                type: VALIDATION_RESOLVED,
                fieldValidationResult: {
                  errors: newErrors,
                  warnings: filteredOutWarnings.concat(warnings.map(attachValidationId))
                }
              })

              return result
            })
          allValidationPromises.push(fieldValidationPromise)
          fieldValidationPromises.push(fieldValidationPromise)
        })
      }
      if (fieldValidationPromises.length >= 1) {
        all(fieldValidationPromises).then(() => {
          dispatchFieldIsValidating(dispatch, field, false)
        })
      }
    })
  })

  return allValidationPromises
}
function fieldValidation (dispatch, getState, fieldValidators, formValue, initialFormValue, all) {
  let fieldsBeingValidated = []
  const allValidationPromises = []
  fieldValidators.forEach(validator => {
    /**
     * Field validator definition
     * @property {String} field field to validate
     * @property {String[]} fields fields to validate
     * @property {Function} validator validation function to validate field/fields. Must return field within error/warning
     * @property {Function[]} validators validation functions to validate field/fields. Must return field within error/warning
     */
    const {field, fields, validator: validatorFunc, validators: validatorFuncs} = validator

    const fieldsToValidate = fields || [field]
    fieldsBeingValidated = fieldsBeingValidated.concat(fieldsToValidate)
    fieldsToValidate.forEach((field) => {
      let fieldValidationPromises = []
      const newValue = _.get(formValue, field)
      const oldValue = _.get(initialFormValue, field)

      // Check if field value has changed
      if (!_.isEqual(newValue, oldValue) || !initialFormValue) {
        dispatchFieldIsValidating(dispatch, field, true)
        const validations = validatorFuncs || [validatorFunc]
            // Send validator formValue, the field we're validating against, and the field's value
        validations.forEach((validatorFunc, index) => {
          const fieldValidationPromise = validatorFunc(formValue, field, newValue)
            .then((result) => {
              const {
                fieldValidationResult: {
                  errors: currentErrors = [],
                  warnings: currentWarnings = []
                } = {}
              } = getState()
              const validationId = `${field}-${index}`
              const filterOutValidationId = (item) => item.validationId !== validationId
              const filteredOutErrors = currentErrors.filter(filterOutValidationId)
              const filteredOutWarnings = currentWarnings.filter(filterOutValidationId)

              // No need to use `aggregateResults as we should never have isRequired
              const {
                errors = [], warnings = []
              } = result.value
              const attachValidationId = (item) => {
                return _.assign({
                  validationId,
                  field
                }, item)
              }
              const newErrors = filteredOutErrors.concat(errors.map(attachValidationId))
              const errorsMappedToDotNotation = mapErrorsFromValidation(newErrors)

              dispatch({
                fieldErrors: errorsMappedToDotNotation,
                type: VALIDATION_RESOLVED,
                fieldValidationResult: {
                  errors: newErrors,
                  warnings: filteredOutWarnings.concat(warnings.map(attachValidationId))
                }
              })

              return result
            })
          allValidationPromises.push(fieldValidationPromise)
          fieldValidationPromises.push(fieldValidationPromise)
        })
      }
      if (fieldValidationPromises.length >= 1) {
        all(fieldValidationPromises).then(() => {
          dispatchFieldIsValidating(dispatch, field, false)
        })
      }
    })
  })

  return allValidationPromises
}
function fieldValidation ( dispatch , getState , fieldValidators , formValue , initialFormValue , all ) { let fieldsBeingValidated = [ ] const allValidationPromises = [ ] fieldValidators . forEach ( validator => { /**
     * Field validator definition
     * @property {String} field field to validate
     * @property {String[]} fields fields to validate
     * @property {Function} validator validation function to validate field/fields. Must return field within error/warning
     * @property {Function[]} validators validation functions to validate field/fields. Must return field within error/warning
     */ const { field , fields , validator : validatorFunc , validators : validatorFuncs } = validator const fieldsToValidate = fields || [ field ] fieldsBeingValidated = fieldsBeingValidated . concat ( fieldsToValidate ) fieldsToValidate . forEach ( ( field ) => { let fieldValidationPromises = [ ] const newValue = _ . get ( formValue , field ) const oldValue = _ . get ( initialFormValue , field ) // Check if field value has changed if ( ! _ . isEqual ( newValue , oldValue ) || ! initialFormValue ) { dispatchFieldIsValidating ( dispatch , field , true ) const validations = validatorFuncs || [ validatorFunc ] // Send validator formValue, the field we're validating against, and the field's value validations . forEach ( ( validatorFunc , index ) => { const fieldValidationPromise = validatorFunc ( formValue , field , newValue ) . then ( ( result ) => { const { fieldValidationResult : { errors : currentErrors = [ ] , warnings : currentWarnings = [ ] } = { } } = getState ( ) const validationId = ` ${ field } ${ index } ` const filterOutValidationId = ( item ) => item . validationId !== validationId const filteredOutErrors = currentErrors . filter ( filterOutValidationId ) const filteredOutWarnings = currentWarnings . filter ( filterOutValidationId ) // No need to use `aggregateResults as we should never have isRequired const { errors = [ ] , warnings = [ ] } = result . value const attachValidationId = ( item ) => { return _ . assign ( { validationId , field } , item ) } const newErrors = filteredOutErrors . concat ( errors . map ( attachValidationId ) ) const errorsMappedToDotNotation = mapErrorsFromValidation ( newErrors ) dispatch ( { fieldErrors : errorsMappedToDotNotation , type : VALIDATION_RESOLVED , fieldValidationResult : { errors : newErrors , warnings : filteredOutWarnings . concat ( warnings . map ( attachValidationId ) ) } } ) return result } ) allValidationPromises . push ( fieldValidationPromise ) fieldValidationPromises . push ( fieldValidationPromise ) } ) } if ( fieldValidationPromises . length >= 1 ) { all ( fieldValidationPromises ) . then ( ( ) => { dispatchFieldIsValidating ( dispatch , field , false ) } ) } } ) } ) return allValidationPromises }
Field validation. Only validate if field has changed.
Meant for expensive validations like server side validation
@function fieldValidation
@param  {Function} dispatch        Redux store dispatch
@param  {Function} getState        Function that returns current state of store
@param  {Array<Object>} fieldValidators     Array of field validators
@param  {Object} formValue           value of what changed
@param  {Object} initialFormValue    initial value before change
@param  {Function} all    framework specific Promise.all method
@returns {Array<Promise>} Array of field validation promises
Field validation . Only validate if field has changed . Meant for expensive validations like server side validation