4

I have a Redux form which is working as it should, except one thing: I need to create an array of checkboxes, so that the user can choose between multiple options.

In HTML/PHP one would write something like that:

<form>
    …
    <input type="checkbox" name="item[]" value="120" />
    <input type="checkbox" name="item[]" value="231" />
    …
</form>

So on Serverside one would receive an array like so (assuming each box is checked): $item = [120, 231], where each item in the array corresponds to the value of the checkbox.

Doing the same with a redux-form like so:

let items = [{name:…, value:…}, …];

<form>
  {items.map(item => {
    <Field component="input" 
           type="checkbox"
           name={item.name + '[]'} 
           value={item.value}
  })}
</form>

results in those inputs: <input type="checkbox" name="item[]" value="true" />, what is not what I would expect. Additionally, checking on checkbox, checks each of the array.

So I changed the name attribute of the <Field /> to

name={`item[${item.value}]`}

what makes the checkboxes work as expected, but in turn result in that data when submitted:

 {
           //index: 0,   1,     ,…, 120, 121, …    ,231, …                      
     item: [undefinded,undefined,…,true,undefined,…,true,undefined,…]
 }

So my Question is: Am I wrong with the creation of the checkboxes, especially their names, or do have to transform the data, once at initialization time and a second time on submit?

If I have to transform the data, where would be the best place for that?

2
  • remove value attribute. Commented Dec 9, 2016 at 19:47
  • Old PHP way was the only way :) Commented Mar 5, 2021 at 11:50

2 Answers 2

7

This is what I ended up doing:

<Field component="input" 
      type="checkbox"
      name={`item.${item.value}`} />

This gives you an object (rather than an array) as the output data structure. It's not quite what you asked for but it is convenient (and, IMO, more natural than other options that require searching the array when a value needs to be removed). Instead of getting [120, 231] you get

{
    120: true,
    231: true,
    165: false // be aware that things that have been checked, and then unchecked, will be explicitly marked false
}

If you want to convert it to an array by finding keys with truthy values, that's a simple thing to do onSubmit(). I'm using lodash: _.keys(_.pickBy(itemValue)) does the conversion quite nicely.

Sign up to request clarification or add additional context in comments.

Comments

0

You can render the array of checkboxes/items as below, and keep track of the checked checkboxes using the onChange event. For example use a selectedItems array on the state, and add/remove items on the onItemChange implementation. On form submit handler you will have all checked items available on the state.

{
  items.map((item, index) => {
    return (
      <div className="checkbox" key={ index }>
        <label>
          <input type="checkbox"
            onChange={ this.onItemChange.bind(this, index) } />
            { item.name }
        </label>
      </div>
    );
  })
}

3 Comments

Binding in render funcion is a bad practice. Do in in constructor.
@Anarion This is generally true, however in this instance he his mapping through an array of items and binding onItemChange to the index to consume the input value. This is a common pattern.
@Splitty isn't this what I suggested?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.