import Observer from "fast-observer" ; import isEqual from "lodash/isEqual" ; import cloneDeep from "lodash/cloneDeep" ; import { checkValidations } from "./validation" ; import { FormController , Validation , InputMode , Values , Errors , InputValidations } from "./types" ; /**
 *
 * Form is a singleton which gets passed into an <Input />. It holds realtime
 * data on all errors and values within a collections of inputs.
 */ export default class Form { observer : Observer = new Observer ( ) ; private initialValues : Values = { } ; private inputValidations : InputValidations = { } ; private values : Values = { } ; private errors : Errors = { } ; private forceCheck : boolean = false ; constructor ( initialValues = { } ) { this . values = cloneDeep ( initialValues ) ; this . initialValues = cloneDeep ( initialValues ) ; } inputMode ( inputName ) { if ( this . forceCheck ) { return InputMode . Dirty ; } if ( this . initialValues [ inputName ] === undefined ) { return InputMode . Unstable ; } else if ( ! isEqual ( this . initialValues [ inputName ] , this . values [ inputName ] ) ) { return InputMode . Dirty ; } return InputMode . Clean ; } setInitialValues ( values ) { for ( const key in values ) { this . setInitialValue ( key , values [ key ] ) ; } return this ; } setValues ( values ) { for ( const key in values ) { this . setValue ( key , values [ key ] ) ; this . observer . publishFast ( `${ key }.setValue` , values [ key ] ) ; } return this ; } async forceValidations ( ) { this . forceCheck = true ; for ( const key in this . values ) { await this . observer . publishFast ( `${ key }.validate` ) ; } return this ; } async validate ( inputName ) { let errors = [ ] ; if ( this . inputValidations [ inputName ] ) { errors = await checkValidations ( this . inputValidations [ inputName ] , this . getValue ( inputName ) ) ; } this . setErrors ( inputName , errors ) ; return errors ; } setValue ( inputName , value ) { this . values [ inputName ] = value ; } setInitialValue ( inputName , value ) { this . initialValues [ inputName ] = value ; } setErrors ( inputName , value ) { this . errors [ inputName ] = value ; } getValue ( inputName ) { return cloneDeep ( this . values [ inputName ] ) ; } getValues ( ) { return cloneDeep ( this . values ) ; } getErrors ( inputName ) { return cloneDeep ( this . errors [ inputName ] ) ; } setValidations ( inputName , validations ) { this . inputValidations [ inputName ] = validations ; } hasErrors ( ) { for ( const key in this . errors ) { const e = this . getErrors ( key ) ; if ( e && e . length ) { return true ; } } return false ; } }