Options
All
  • Public
  • Public/Protected
  • All
Menu

Class FormState<T>

instances of this class will be responsible for managing logic and binding Models Validators and components together. For relevant usages refer to makeFormStateWithModel and makeFormModel

Type parameters

Hierarchy

Index

Constructors

Properties

anyChangeListeners: Record<string, (value: any, model: FormModel<any>, property: string, options?: InputUseOptions) => void> = {}
lastSubscribedComponentKey: number = 0

tracks last subscribed component key reference, each time component subscribes value be incremented, and such incremented value be used as key under which component will be subscribed

model: T

every form state has one root model. Root model is instance of FormModel nested models can reside as well on root model.

subscribedEntries: {} = {}

will use {@see lastSubscribedComponentKey} and put under it {@see ISubscribedEntry}

Type declaration

touched: boolean = false

if any managed property was at least once updated, will become true. used for logic to specify identify if user started using the form.

remark

this is wired if model gets updated through setValue or onChangeEventHandler or on change handlers, returned by useForInput()

version: number = 0

state version be incremented on each update each time component renders, it's entry be updated with the version of this state. when it comes to decision if component should be updated, the version of update be compared to last rendered version, if they're same, or rendered version is bigger than state version it will be skipped. effectively this insures that component be updated exactly once for each version, preventing rerendering for e.g. nested components subscribed for same state.

Methods

  • _update(): void
  • addRuntimeValidationAsDefaultToValidator(model: FormModel<any>, property: any, options: InputUseOptions): undefined | { skipValidationOnChange?: boolean; validateOnBlur?: boolean; additionallyOnChange?: any }
  • used for ad hoc validations, whenever you provide in methods that accept InputUseOptions a validate, it will be added as default validation to a validator

    Parameters

    Returns undefined | { skipValidationOnChange?: boolean; validateOnBlur?: boolean; additionallyOnChange?: any }

  • getNextSubscribedComponentId(): number
  • isValid(options?: { validate: boolean }): boolean
  • calls isValid on validator {@see ModelValidator.isValid}.

    Parameters

    • Optional options: { validate: boolean }

    Returns boolean

  • makeInputProps(property: keyof this["model"], options?: InputUseOptions): InputPropsForModel
  • makeInputPropsForModel<T>(model: T, property: Extract<keyof T, string>, options?: InputUseOptions): InputPropsForModel
  • For usage in no edgecase, close to uncontrolled input scenarios that don't require performance tweaking. Usefull for cases when you work with standard html input. Return result shall be passed to an input as spreaded props.

    example
    const userFormState = new UserFormState(new User())
    const UserForm = () => {
    const formState = userFormState.use()
    const model = formState.model

    return <input {...formState.makeNativeInputProps(model, 'firstName')}/>
    // value will be set from model.firstName
    // onChange will set model.firstName = event.target.value
    // default validation will run -
    }

    Type parameters

    Parameters

    • model: T

      model on which input will set value

    • property: Extract<keyof T, string>

      property of model which will be updated

    • Optional options: InputUseOptions

      InputUseOptions different options where you can e.g. override validation behaviour

    Returns InputPropsForModel

    call returns following: return values are subset of return of useForInput, that can be passed directly to native inputs.

    • onChange - same as onChangeEventHandler, just takes event, gets it's value and passes to func that assigns on model and runs default stuff like validation
    • onBlur - if you specified options.validateOnBlur, validate func be run
    • value - value from model.modelData[property]
  • makeOnChangeHandler<T>(model: T, property: Extract<keyof T, string>, options?: InputUseOptions): (e: ChangeEvent<any>) => void
  • makes a changeEvent handler for updating model proeprty

    Type parameters

    Parameters

    • model: T
    • property: Extract<keyof T, string>
    • Optional options: InputUseOptions

    Returns (e: ChangeEvent<any>) => void

      • (e: ChangeEvent<any>): void
      • Parameters

        • e: ChangeEvent<any>

        Returns void

  • onAnyChange(__namedParameters: { listenerName: string; handler: any }): void
  • will add named listener (named to avoid duplication/double firing), that will run whenever onValueChange, setValue will run

    Parameters

    Returns void

  • onChangeEventHandler<T>(e: ChangeEvent<any>, model: T, property: Extract<keyof T, string>, options?: InputUseOptions): void
  • onValueChange<T>(value: any, model: T, property: Extract<keyof T, string>, options?: InputUseOptions): void
  • runValidate<T>(value: any, model: T, property: Extract<keyof T, string>, options?: InputUseOptions): void
  • setValue<T>(value: any, model: T, property: Extract<keyof T, string>, options?: InputUseOptions): void
  • This is primary method to update the property on model from input. Other on change methods, call this anyway.

    Type parameters

    Parameters

    • value: any

      new value that be set

    • model: T

      model on which value be set

    • property: Extract<keyof T, string>

      property to update value on

    • Optional options: InputUseOptions

    Returns void

  • unsubscribe(id: number): void
  • update(): void
  • subscribes component to this state represented by extending instance, behind the scenes will call useState using someNumber as it's initial state. the updateState from called useState and supplied options, will be stored under generated key on subscribed entries (simple object on this instance), any time update is called, all entries be traversed and corresponding update func be called, leading to update. on unmount entry will be deleted by the key it was subscribed under.

    as options may be passed:

    updateDeps?: a function that returns an array of dependencies. Before the next update, same func be called, and it's contents compared against the result of previous call. If both are same, update will be ignored onUnsubscribed?: any cleanup function on component's unmount. options are optional

    example
    someState.use() // on update call will trigger update for this component
    someState.use({
    updateDeps: (state) => [state.foo, state.bar]
    }) // will only update if return func of updateDeps is different since last update
    // comparison will happen shallowly and strict.


    //---------------------

    // how it basically works:
    class SomeState extends SubscriptionState {
    counter = 1

    updateCounter = () => {
    this.counter += 1
    this.update()
    }
    }

    SomeComponent
    someState.use()

    // someState.subScribedEntries // {1: {updateState, ...}}

    OtherComponent
    someState.use()

    // someState.subScribedEntries // {2: {updateState, ...}}
    // someState.update() // will just iterate over subscribed components and call update function so they're rerendered
    // that's it.

    Parameters

    Returns FormState<T>

  • For usage in custom input wrappers, input/ui lib adaptations. This method calls use() behind the scenes and subscribes to formState changes. But it will not update on every change but only when stuff relevant to property is changed.

    Call will also return a set of controls you can pass to input components like getValue(), onChange() on valueChange() and etc.

    example

    usage in custom input wrapper:

    const MyInput: React.FC<{
    formState: FormState
    model: FormModel
    property: string
    }> = ({ formState, model, property }) => {
    // call use() with update dependencies, so updates only on relevant changes
    const controls = formState.useForInput(model, property)
    const error = controls.getFirstError()

    return (
    <div className="componentSection">
    <input
    type="text"
    value={controls.getValue() as any}
    onChange={controls.onChange}
    />
    {error && <p className="inputError">{error}</p>}
    <button onClick={() => console.log(controls)}>
    log useInput controls
    </button>
    </div>
    )
    }
    remark

    all returned properties are getter functions. This was done due to perf reasons.

    Type parameters

    Parameters

    Returns UseForInputReturns<T>

    onChange - handler for wrapped in ChangeEvent value, will get the value and pass to same onValueChange

  • validate(options?: FormStateValidateArgs<FormState<T>>): boolean

Generated using TypeDoc