Home

Awesome

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

Control

APIs

Form

Control

Validators

Default validators
ValidatorOptions
required-
minLengthlength: number
maxLengthlength: number
patternpattern: RegExp
email-
equalToControlcontrolName: 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 };
})

Inspired by Angular Forms.