gcanti / tcomb-form

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

Error trying to implement the TagsComponent example #280

Closed Industrial closed 8 years ago

Industrial commented 8 years ago

Hi.

I have a list of items (technologies) in my form that I'd like to use the tags component for that is used in the GUIDE.md;

...

    const options = {
      fields: {
        aboutMe: {
          type: 'textarea'
        },

        experience: {
          item: {
            fields: {
              shortDescription: {
                type: 'textarea'
              },

              technologies: {
                factory: TagsComponent
              }
            }
          }
        }
      }
    };

    return (
      <Grid fluid={true}>
        <Row>
          <Col xs={12}>
            <form onSubmit={this.handleSubmit}>
              <Form
                ref="form"
                type={EmployeeSchema}
                options={options}
                value={this.props.value}
              />
              <Button type="submit" bsStyle="primary">Save</Button>
            </form>
          </Col>
        </Row>
      </Grid>
    );
  }

...

where TagsComponent is

const React = require('react');
const tcombForm = require('tcomb-form');
const TagsInput = require('react-tagsinput');

class TagsComponent extends tcombForm.form.Component {
  getTemplate() {
    return (locals) => {
      return (
        <TagsInput value={locals.value} onChange={locals.onChange} />
      );
    };
  }
}

export default TagsComponent;

When I expand my form to add an experience item which has the TagsComponent I get Uncaught Error: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of Struct..

Did I implement it wrongly?

gcanti commented 8 years ago

Hi, The problem seems that react-tagsinput (I'm using version 3.0.3) requires an array as value (i.e. it doesn't handle null nor undefined). You must ensure the value passed in is an array, for example with a transformer

class TagsComponent extends t.form.Component {

  static transformer = {
    format: (value) => value || [], // <= ensure an array
    parse: (value) => value
  }

  getTemplate() {
    return (locals) => {
      return (
        <TagsInput value={locals.value} onChange={(tags) => locals.onChange(tags)} />
      )
    }
  }

}

Also, you may want to clone a default template and leverage the built-in features (automatic labels, help messages, and so on...)

const template = t.form.Form.templates.textbox.clone({
  // override just the textbox rendering...
  renderTextbox: (locals) => <TagsInput value={locals.value} onChange={(tags) => locals.onChange(tags)} />
})

class TagsComponent extends t.form.Component {

  static transformer = {
    format: (value) => value || [],
    parse: (value) => value
  }

  getTemplate() {
    return template
  }

}
gcanti commented 8 years ago

Closing for inactivity. Feel free to reopen if it's still a problem.