19

Having trouble getting my POST arrays to show all checkbox values from my form.

I have a form set up as follows:

<form name='foo' method='post' action=''>
    <table>
       <tr>
          <td class='bla'>Checkbox: <input type='checkbox' name='cBox[]'/></td>
      </tr>
       <tr>
          <td class='bla'>Checkbox: <input type='checkbox' name='cBox[]'/></td>
      </tr>
       <tr>
          <td class='bla'>Checkbox: <input type='checkbox' name='cBox[]'/></td>
      </tr>
   </table>
</form>

I have a button at the bottom bound to a jquery function that adds 5 more empty rows to the form (hence the arrays for the input name cBox[]).

Now, the problem. Lets say the first checkbox is unchecked, and the last 2 are checked. When I output the values (using PHP print_r for debugging), I will get:

Array ( [0] => on [1] => on)

For some reason, the array does not contain any value for unchecked checkboxes.

I have seen some solutions where a hidden variable is passed with each checkbox, but can this solution be implemented in my situation (using arrays)?

SpaghettiMonster
  • 620
  • 1
  • 8
  • 17

6 Answers6

23

That behavior is not surprising, as the browser doesn't submit any value for checkboxes that are unchecked.

If you are in a situation where you need to submit an exact number of elements as an array, why don't you do the same thing you do when there's an id of some sort associated with each checkbox? Just include the PHP array key name as part of the <input> element's name:

  <tr>
                                                       <!-- NOTE [0] --->
      <td class='bla'>Checkbox: <input type='checkbox' name='cBox[0]'/></td>
  </tr>
   <tr>
      <td class='bla'>Checkbox: <input type='checkbox' name='cBox[1]'/></td>
  </tr>
   <tr>
      <td class='bla'>Checkbox: <input type='checkbox' name='cBox[2]'/></td>
  </tr>

That still leaves you with the problem that unchecked boxes will still not be present in the array. That may or may not be a problem. For one, you may really not care:

foreach($incoming as $key => $value) {
    // if the first $key is 1, do you care that you will never see 0?
}

Even if you do care, you can easily correct the problem. Two straightforward approaches here. One, just do the hidden input element trick:

  <tr>
      <td class='bla'>
        <input type="hidden" name="cBox[0]" value="" />
        Checkbox: <input type='checkbox' name='cBox[0]'/>
      </td>
  </tr>
   <tr>
      <td class='bla'>
        <input type="hidden" name="cBox[1]" value="" />
        Checkbox: <input type='checkbox' name='cBox[1]'/>
      </td>
  </tr>

And two, which I find preferable, fill in the blanks from PHP instead:

// assume this is what comes in:
$input = array(
    '1' => 'foo',
    '3' => 'bar',
);

// set defaults: array with keys 0-4 all set to empty string
$defaults = array_fill(0, 5, '');

$input = $input + $defaults;
print_r($input);

// If you also want order, sort:

ksort($input);
print_r($input);

See it in action.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • Thanks Jon. I will look into this solution. My only concern is the unique names. I have an unknown number of inputs as they are added with jquery .clone(). Also, your link does not work, can you use a url shortener? – SpaghettiMonster Nov 02 '11 at 23:40
  • 1
    @SpaghettiMonster: Link fixed (copy paste fail). Even if cloning, you can chain a couple of extra jQuery methods to set the name after the clone is made. – Jon Nov 02 '11 at 23:46
  • Thanks Jon. I added a few more lines of jQuery to count the number of existing rows and use this to increment the array positions, and used your code above. Works 100% perfectly! :) – SpaghettiMonster Nov 03 '11 at 00:36
  • Good answer, thanks for mentioning the ksort() step at the end, that was necessary in my case! – Deemoe Apr 20 '14 at 05:05
7

ONE TRICK is to override the checkbox value, if checked. otherwise its value will be 0.

<form>
  <input type='hidden' value='0' name="smth">
  <input type='checkbox' value='1' name="smth">
</form>
T.Todua
  • 53,146
  • 19
  • 236
  • 237
  • While your logic is true this doesn't answer the question because if you have an array than then foreach with key pair will be incorrect – Chad Priddle Oct 07 '15 at 18:38
3

Try

<input type='checkbox' value="XXX" name='cBox[]'/>
<input type='checkbox' value="YYY" name='cBox[]'/>
<input type='checkbox' value="ZZZ" name='cBox[]'/>

Checkboxes work that way. If it is checked, only then the value is posted.

Mārtiņš Briedis
  • 17,396
  • 5
  • 54
  • 76
  • I tried this, and the result I get is: Array ( [0] => YYY [1] => ZZZ ). Unfortunately I cannot give each input unique values as the can be dynamically added via the jquery function I spoke of. – SpaghettiMonster Nov 02 '11 at 23:17
  • 1
    Well then replace the YYY, ZZZ with the values you need. Then just check, if $_POST['cBox'] (which is an array) contains needed values. – Mārtiņš Briedis Nov 02 '11 at 23:19
2

If you are handling dynamic checkbox array, you can try this:

HTML:

<label>
  <input type="hidden" name="cBox[]" value="" />
  <input type="checkbox" class="checkbox" value="on" />
</label>
<label>
  <input type="hidden" name="cBox[]" value="" />
  <input type="checkbox" class="checkbox" value="on" />
</label>
<!-- extend -->

Javascript (jQuery):

$(document).on("change", "input.checkbox", function() {

    var value = $(this).is(":checked") ? $(this).val() : null;

    $(this).siblings("input[name='cBox[]']").val(value);    
});

Backend result (If only checked the second one):

// PHP $_POST['cBox']
Array
(
    [0] => 
    [1] => on
)

In this implement, the checkboxes are used to controller each hidden input in a group.

For displaying page, You can render each inputs pair back by assigning the value into hidden inputs and marking checkboxes as checked.

Nick Tsai
  • 3,799
  • 33
  • 36
0

In controller:

request()->merge(['cBox' => request()->input('cBox', [])]);

kjdion84
  • 9,552
  • 8
  • 60
  • 87
0

Try setting a value to each checkbox, of 1 or true.

<input type='checkbox' value='1' name='cBox[1]'/>

that may be why its not sending anything?

geilt
  • 807
  • 8
  • 9