gcanti / tcomb-form

Forms library for react
https://gcanti.github.io/tcomb-form
MIT License
1.16k stars 136 forks source link

Summary Box for errors in form layout template #212

Closed benmonro closed 8 years ago

benmonro commented 8 years ago

I have a form layout template in which I'd like to display a summary list of all the errors on the form, as opposed to the inline errors next to each element. I have created my own custom templates for each component as well as one for the form. My thought is to do something like this:

function formLayout(locals) {
  return (<div>
    <ul>
     {locals.errors && locals.errors.map(error => <li>{error.message}</li>)}
    </ul>
    {locals.inputs.myInput1}
    {locals.inputs.myInput2}
  </div>
  );
}

var options = {template:formLayout, fields: {}}
benmonro commented 8 years ago

well I found a hack that serves my purpose but I'm not crazy about it. Basically I use tcomb-validation directly in the template function and in the onChange handler for the form, I update the options.hasError like this (to ensure the errors aren't displayed by default):


    onChange(value, path) {
        var result = this.refs.form.validate();

            this.setState({
                options: t.update(this.state.options, {hasError: {'$set':result.errors.length > 0}}),
                value
            })
        }
gcanti commented 8 years ago

An example using the default locals.error and locals.hasError

var Type = t.struct({
  name: t.String,
  surname: t.String
});

var App = React.createClass({

  getInitialState() {
    return {
      options: {},
      value: {}
    };
  },

  onChange(value) {
    this.setState({value});
  },

  onSubmit(evt) {
    evt.preventDefault();
    var result = this.refs.form.validate();
    if (result.isValid()) {
      console.log(result.value);
    }
    else {
      this.setState({
        options: {
          error: <ul>{result.errors.map((e, i) => <li key={i}>{e.message}</li>)}</ul>,
          hasError: true
        }
      });
    }
  },

  render() {
    return (
      <form onSubmit={this.onSubmit}>
        <t.form.Form
          ref="form"
          type={Type}
          options={this.state.options}
          value={this.state.value}
          onChange={this.onChange}
        />
        <button type="submit" className="btn btn-primary">Save</button>
      </form>
    );
  }

});
benmonro commented 8 years ago

thanks @gcanti that works nicely. I'd prefer to pass the error results to the template rather than render them in the submit button click handler, but this will suffice for my purposes. :)