Skip to content

unexge/foect

Repository files navigation

Foect Build Status npm version

Simple form validation library for React Native.

Installing

Npm

npm i --save foect

Yarn

yarn add foect

Quick Start

import { TextInput, Text, View, Button } from 'react-native';
import Foect from 'foect';

// ...

<Foect.Form
  defaultValue={{
    email: 'john@doe.com'
  }}
  onValidSubmit={model => {
    console.log(model); // { fullName: 'John Doe', email: 'john@doe.com' ... }
  }}
>
  { /* you can use form for triggering submit or checking form state(form.isSubmitted, form.isValid, ...) */ }
  { form => (
    <View>
      { /* every Foect.Control must have a name and optionally validation rules */ }
      <Foect.Control name="fullName" required minLength={2} maxLength={32}>
        { /* you can use control for getting/setting it's value, checking/updating(control.isValid, control.markAsTouched(), ...) it's state, checking it's errors(control.errors.required) */ }
        { control => (
          <View>
            <Text>Full Name</Text>

            <TextInput
              style={{height: 40, borderColor: 'gray', borderWidth: 1}}
              { /* mark control as touched on blur */ }
              onBlur={control.markAsTouched}
              { /* update control's value */ }
              onChangeText={(text) => control.onChange(text)}
              { /* get control's value */ }
              value={control.value}
            />

            { /* check control state and show error if necessary */ }
            { control.isTouched &&
              control.isInvalid && 
              <Text style={{ color: 'red' }}>Please enter your name.</Text> }
          </View>
        ) }
      </Foect.Control>

      <Foect.Control name="password" required pattern={/(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/}>
        { control => (
          <View>
            <Text>Password</Text>

            <TextInput
              style={{height: 40, borderColor: 'gray', borderWidth: 1}}
              secureTextEntry={true}
              onBlur={control.markAsTouched}
              onChangeText={(text) => control.onChange(text)}
              value={control.value}
            />

            { control.isTouched &&
              control.isInvalid && 
              <View>
                { control.errors.pattern ?
                  <Text style={{ color: 'red' }}>Please provide a strong password.</Text> : 
                  <Text style={{ color: 'red' }}>Please enter your password.</Text> }
              </View> }
          </View>
        ) }
      </Foect.Control>

      <Foect.Control name="email" required email>
        { control => (
          <View>
            <Text>Email</Text>

            <TextInput
              style={{height: 40, borderColor: 'gray', borderWidth: 1}}
              keyboardType="email-address"
              onBlur={control.markAsTouched}
              onChangeText={(text) => control.onChange(text)}
              value={control.value}
            />

            { control.isTouched &&
              control.isInvalid && 
              <View>
                <Text>{control.value} is not a valid email.</Text>
              </View> }
          </View>
        ) }
      </Foect.Control>

      { /* submit form */ }
      <Button disabled={form.isInvalid} onPress={() => form.submit()} title="Register" />
    </View>
  ) }
</Foect.Form>

Documentation

Types

type Status = 'INIT' | 'VALID' | 'INVALID';
type Model = { [key: string]: any };
// { firstName: 'John', lastName: 'Doe' }
type Errors = { [key: string]: boolean };
// { required: true, email: true }
type FormErrors = { [name: string]: Errors };
// { firstName: { required: true, minLength: true } }
type Validator = (value: any, config?: any, control?: Control) => ValidatorResult;
type ValidatorResult = null | Errors;

Props

Form

  • children: (form: Form) => Element child renderer function.
  • defaultValue?: Model default values for form.
  • onChange?: (model: Model) => void callback called on value change.
  • onValidSubmit?: (model: Model) => void callback called on valid submit.
  • onInvalidSubmit?: (errors: FormErrors, model: Model) => void callback called on invalid submit.

Control

  • children: (control: Control) => Element child renderer function.
  • name: string control name.
  • [validator: string]: any; validation rules for control.

APIs

Form

  • status: Status form status.

  • errors: FormErrors form errors.

  • isValid: boolean is form valid.

  • isInvalid: boolean is form invalid.

  • isSubmitted: boolean is form submitted.

  • addControl(name: string, control: Control): void adds a new control to form.

  • removeControl(name: string): void removes a control from form.

  • getValue(name: string): any returns value of a control.

  • setValue(name: string, value: any): void sets value for a control.

  • getErrors(name: string): Status returns errors of a control.

  • setErrors(name: string, errors: Errors): void sets errors for a control.

  • validateControl(name: string): void validates a control and updates control state, errors.

  • getStatus(name: string): Status returns status of a control.

  • update(): void force updates form and all child controls.

  • submit(): void submits the form. calls onInvalidSubmit or onValidSubmit callback if provided.

Control

  • value: any control value.

  • form: Form control's form.

  • status: Status control status.

  • errors: Errors control errors.

  • isValid: boolean is control valid.

  • isInvalid: boolean is control invalid.

  • isTouched: boolean is control touched.

  • isUntouched: boolean is control untouched.

  • onChange(value: any): void updates control's value.

  • markAsTouched(): void marks control as touched.

  • markAsUntouched(): void marks control as untouched.

  • runValidation(value: any): Errors runs validation with a value and returns errors.

Validators

Default validators
Validator Options
required -
minLength length: number
maxLength length: number
pattern pattern: RegExp
email -
equalToControl controlName: string
callback (value: any, control: Control) => boolean

Options are passed via props

<Foect.Control
  name="password2"
  myValidator={{foo: 'bar'}}
>

with this definition, myValidator called with ('value of the input', {foo: 'bar'}, controlRef)

You can add your own validators via Foect.Validators.add. Validators must return null on valid value and object with errors on invalid value. For example:

Foect.Validators.add('equalToControl', (val: any, controlName: string, control: Control) => {
  if (null === val) {
    return null;
  }

  return val === control.form.getValue(controlName) ? null : { equalToControl: true };
})
  • Foect.Validators.add(validatorName: string, fn: Validator): void adds a new validator.
  • Foect.Validators.get(validatorName: string): Validator returns a validator.
  • Foect.Validators.has(validatorName: string): boolean returns whether a validator exists.
  • Foect.Validators.delete(validatorName: string): void deletes a validator.

Inspired by Angular Forms.