All files form.js

38.3% Statements 18/47
30% Branches 12/40
40% Functions 4/10
41.86% Lines 18/43
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97          1x 1x 1x 1x 1x                                                                                               3x 3x   3x 3x 2x   3x   3x                       3x 1x   1x           2x         1x 1x      
import React from 'react';
import Validator from 'validatorjs';
 
export default class Form extends React.Component {
  constructor({ initialValues }) {
    super();
    this.state = { values: initialValues || {}, errors: {} };
    this.onChange = this.onChange.bind(this);
    this.validate = this.validate.bind(this);
    this.onBlur = this.onBlur.bind(this);
  }
 
  componentWillReceiveProps({ errors, initialValues }) {
    if (initialValues !== this.props.initialValues)
      this.setState({ initialValues });
 
    if (errors !== this.props.errors) this.setState({ errors });
  }
 
  validate(onClick) {
    let { rules } = this.props;
    let { values } = this.state;
    if (!rules) return onClick(values);
 
    const runner = new Validator(values, rules);
 
    if (runner.fails()) {
      return this.setState({ errors: runner.errors.errors });
    } else this.setState({ errors: {} });
 
    return onClick(values);
  }
 
  onBlur(name) {
    let { rules } = this.props;
    let { errors, values } = this.state;
    if (!rules || !rules[name]) return;
 
    const runner = new Validator(
      { [name]: values[name] },
      { [name]: rules[name] }
    );
 
    if (runner.fails() && values[name]) {
      return this.setState({ errors: { ...errors, ...runner.errors.errors } });
    }
    if (errors[name])
      return this.setState({ errors: { ...errors, [name]: null } });
  }
 
  onChange({ target }) {
    let { values } = this.state;
    values[target.name] = target.value;
    this.setState({ values });
  }
 
  renderChildren(children) {
    return React.Children.map(children, child => {
      Iif (!child || !child.props) return child;
 
      let children = child.props.children;
      if (child.props.children && typeof child.props.children !== 'string')
        children = this.renderChildren(child.props.children);
 
      let { values, errors } = this.state;
 
      Iif (child.props.name)
        return React.cloneElement(child, {
          children,
          onChange: this.onChange,
          onBlur: () => this.onBlur(child.props.name),
          error: errors[child.props.name] &&
            typeof errors[child.props.name] !== 'string'
            ? errors[child.props.name][0]
            : errors[child.props.name] || '',
          value: values[child.props.name] || '',
        });
 
      if (child.props.submit) {
        let { submit, ...otherProps } = child.props;
 
        return React.createElement(child.type, {
          ...otherProps,
          children,
          onClick: () => this.validate(child.props.onClick),
        });
      }
      return React.cloneElement(child, { children });
    });
  }
 
  render() {
    let { children, rules, initialValues, ...props } = this.props;
    return <div {...props}>{this.renderChildren(children)}</div>;
  }
}