gcanti / tcomb-form

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

CheckBox List #249

Closed JoaoCnh closed 8 years ago

JoaoCnh commented 8 years ago

Hey

I want to have a checkbox list. Imagine the Models User and Car.

When creating a user I can choose one or more cars. So I create the User struct and Car struct.

I tried using t.list(Car) but it doesn't work.

Am I missing something? Or is this just not possible?

gcanti commented 8 years ago

Hi, Could you elaborate a little bit on your use case? Could you post the models and what's the expected behaviour?

JoaoCnh commented 8 years ago

Let's say a User is made of a name and a list of cars.

a Car is just made up of an Id and Name

so it would just be a list of checkboxes that the users could select. He could choose just one or more.

I'm struggling with that and having that mapped to the state and handling them.

gcanti commented 8 years ago

Let's say a User is made of a name and a list of cars.

So something like this:

const Car = t.struct({
  id: t.String,
  name: t.String
});

const User = t.struct({
  name: t.String,
  cars: t.list(Car)
});

But then you can't simply represent the list of car with checkboxes.

Maybe you want to build the User type dynamically (if the list of cars is fixed):

// a fixed list of cars
const cars = [
  {
    id: 'porche',
    name: 'Porche'
  },
  {
    id: 'ferrari',
    name: 'Ferrari'
  }
];

const fields = {
  name: t.String
};

const options = {
  fields: {}
};

cars.forEach((car) => {
  fields[car.id] = t.Boolean; // build the checkbox
  options.fields[car.id] = { label: car.name }; // give it a label
});

const User = t.struct(fields);
JoaoCnh commented 8 years ago

I'll try that when I get to work tomorrow and I'll edit with feedback. But looks good. You understood what I wanted.

EDIT: How would I approach the formLayout with this?

I would like to place the normal form on one bootstrap and the checkbox list in another. I've tried applying the bootstrap classes but in the form layout it never works

JoaoCnh commented 8 years ago

Here's where I'm at:

I was able to do a layout like I wanted. What I'm trying to do now is have the value come out like this, for example I'm creating a User who has cars

user: { username: 'foo', blablabla cars: [ { cars here } ] }

with the method above I'm getting each Id as a field and for me to manage that is quite bothersom. Does anyone see a way out of this?

gcanti commented 8 years ago

Hi @JoaoCnh, if it can be helpful, this is an example I wrote yesterday for a project of mine (using react-select)

import React from 'react'
import t from 'tcomb-form'
import ReactSelect from 'react-select'

const interests = [
  {value: 'Calligraphy', label: 'Calligraphy'},
  {value: 'Cosplaying', label: 'Cosplaying'},
  {value: 'Homebrewing', label: 'Homebrewing'},
  {value: 'Puzzles', label: 'Puzzles'},
  {value: 'Sudoku', label: 'Sudoku'}
]

const tags = t.form.Form.templates.select.clone({
  renderSelect: (locals) => {
    function onChange(options) {
      const values = (options || []).map(({value}) => value)
      locals.onChange(values)
    }
    return <ReactSelect multi options={interests} value={locals.value} onChange={onChange} />
  }
})

class ReactSelectFactory extends t.form.Component {

  getTemplate() {
    return tags
  }

}

ReactSelectFactory.transformer = t.form.List.transformer

const Type = t.struct({
  name: t.String,
  tags: t.list(t.String)
})

const options = {
  fields: {
    tags: {
      factory: ReactSelectFactory
    }
  }
}

const App = React.createClass({

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

  onSubmit(evt) {
    evt.preventDefault()
    const v = this.refs.form.getValue()
    if (v) {
      console.log('ok', v) // eslint-disable-line
    }
  },

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

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

})

export default App
gcanti commented 8 years ago

Closing for inactivity. Feel free to reopen.