aqibjr1
aqibjr1

Reputation: 594

Capturing the value from multiple checkboxes with same value

I'm stuck here. I'm basically have a set up where a user can dynamically add a new "item" row and inside each row is a checkbox. When the checkbox is checked, the value in the DB should be stored as 1 and if not, it is automatically stored as 0 (I have written up all this code).

However, I've got a much more fundamental problem: when a checkbox isn't checked, nothing is posted and thus my array's size is not what I expect it to be. Below, is some sample code which highlights my problem:

<form action="" method="post" target="_blank">
Enter name for item 1 <input type="text" name="item_name[]" required>  <input type="checkbox" name="item_checked[]" value="yes"> <br />
Enter name for item 2 <input type="text" name="item_name[]" required>  <input type="checkbox" name="item_checked[]" value="yes"> <br />
Enter name for item 3 <input type="text" name="item_name[]" required>  <input type="checkbox" name="item_checked[]" value="yes"> <br />
<input type="submit" value="Submit">
</form>

<?php
for($i = 0; $i < count($_POST['item_name']); $i++){
    $itemName = $_POST['item_name'][$i];
    $itemChecked = "no";
    if(isset($_POST['item_checked'][$i]) && $_POST['item_checked'][$i] == "yes"){
        $itemChecked = "yes";   
    }
    echo "item_name: $itemName, i: $i, itemChecked $itemChecked <br />";
}

?>

Simply speaking, the item_name textboxes are mandatory. The checkboxes (obviously) aren't. What I would like for to happen is if I check only the second checkbox, then this is registered in the POST data (but currently, when nothing is checked, nothing is posted so the value of $i is different and this it is set for the first item).

EDIT: I've added my entire (simplified) version of the code including the functionality where I add and remove rows, so you can better understand the issue:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script>
$(document).ready(function(){
    $(".addCF").click(function(){
        $("#products").append('<tr><td>Enter name for item <input type="text" name="item_name[]"> <input type="checkbox" name="item_checked[]" value="yes"> <a href="javascript:void(0);" class="remCF tip" title="Remove this item">Remove</a></td></tr>');
    });
    $("#products").on('click','.remCF',function(){
        $(this).parent().parent().remove();
    });
});
</script>


<a href="javascript:void(0);" class="addCF">Add</a>


<form action="" method="post" target="_blank">

<table id="products">
<tr><td>Enter name for item <input type="text" name="item_name[]">  <input type="checkbox" name="item_checked[]" value="yes"> <a href="javascript:void(0);" class="remCF tip" title="Remove this item">Remove</a></td></tr>

</table>

<input type="submit" value="Submit">
</form>


<?php
for($i = 0; $i < count($_POST['item_name']); $i++){
    $itemName = $_POST['item_name'][$i];
    $itemChecked = "no";
    if(isset($_POST['item_checked'][$i]) && $_POST['item_checked'][$i] == "yes"){
        $itemChecked = "yes";   
    }
    echo "item_name: $itemName, i: $i, itemChecked $itemChecked <br />";
}

?>

TL, DR: The checkbox is not correctly posted with the item.

Upvotes: 1

Views: 1404

Answers (4)

aqibjr1
aqibjr1

Reputation: 594

Thanks everybody. I took inspiration from Patrick's javascript idea and managed to solve it in this way. A bit fiddly, but I think it works fine!

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script>
$(document).ready(function(){
    $(".addCF").click(function(){
        $("#products").append('<tr><td>Enter name for item <input type="text" name="item_name[]"> <input class="vatcheckbox" type="checkbox" name="item_checked[]" value="" data-basename="item_checked"> <a href="javascript:void(0);" class="remCF tip" title="Remove this item">Remove</a></td></tr>');
    updateValues();
    });
    $("#products").on('click','.remCF',function(){
        $(this).parent().parent().remove();
    updateValues();
    });



function updateValues()
    {

        $("tr").each(function(i){ 
            $(this).children('td').each(function(){
                $(this).children('input[type=checkbox]').each(function(){
                    $(this).attr("value", $(this).data("basename")+"["+i+"]");
                });
            });
        });

    }


});
</script>


<a href="javascript:void(0);" class="addCF">Add</a>


<form action="" method="post" target="_blank">

<table id="products">
<tr><td>Enter name for item <input type="text" name="item_name[]">  <input type="checkbox" class="vatcheckbox" name="item_checked[]" data-basename="item_checked" value="item_checked[0]"> <a href="javascript:void(0);" class="remCF tip" title="Remove this item">Remove</a></td></tr>

</table>

<input type="submit" value="Submit">
</form>


<?php


if(isset($_POST['item_checked'])){
    $itemsChecked = array();

    foreach($_POST['item_checked'] as $item){
        $pattern = '/(item_checked\[)([0-9]+)(\])/';
        $success = preg_match($pattern, $item, $match);
        array_push($itemsChecked, $match[2]);
    }
}


if(isset($_POST['item_name'])){

    for($i=0; $i<count($_POST['item_name']); $i++){
        echo $_POST['item_name'][$i];
        if(in_array($i, $itemsChecked)){
            echo " checked";
        }
        echo "<br />";
    }

}


?>

The rows are counted by javascript then these are attached to the value field in the respective checkboxes. I then use some regex to extract the row number, storing this in an array. Then when I'm looping through my item names, I just checked if the current index was in the aforementioned array, if so I print "checked" (obviously you can set a varibable here). Thanks everyone!

Upvotes: 1

Patrick Q
Patrick Q

Reputation: 6393

Since you are dynamically adding and removing rows, you basically need something that will also dynamically re-index your input arrays. So every time you add or remove a row, the script will iterate through all of the current rows and assign the zero-based row number as the index for the inputs in that row.

Here's the javascript that you can use:

$(document).ready(function(){
    $(".addCF").click(function(){

        $("#products").append('<tr><td>Enter name for item <input type="text" name="item_name[]" data-basename="item_name"> <input type="checkbox" name="" value="yes" data-basename="item_checked"> <a href="javascript:void(0);" class="remCF tip" title="Remove this item">Remove</a></td></tr>');
        updateNames();
    });
    $("#products").on('click','.remCF',function(){
        $(this).parent().parent().remove();
        updateNames();
    });

    function updateNames()
    {

        $("tr").each(function(i){ 
            $(this).children('td').each(function(){
                $(this).children('input').each(function(){
                    $(this).attr("name", $(this).data("basename")+"["+i+"]");
                });
            });
        });

    }
});

And here's your updated HTML:

<a href="javascript:void(0);" class="addCF">Add</a>


<form action="" method="post" target="_blank">

<table id="products">
<tr><td>Enter name for item <input type="text" name="item_name[0]" data-basename="item_name">  <input type="checkbox" name="item_checked[0]" data-basename="item_checked" value="yes"> <a href="javascript:void(0);" class="remCF tip" title="Remove this item">Remove</a></td></tr>

</table>

<input type="submit" value="Submit">
</form>

Your PHP should not need to change.

Live example of the HTML and javascript

Upvotes: 2

Naizy Monteiro
Naizy Monteiro

Reputation: 76

To add uniqueness: In php add directly

<form action="" method="post" target="_blank">
Enter name for item 1 <input type="text" name="item_name[0]" required>  <input type="checkbox" name="item_checked[0]" value="yes"> <br />
Enter name for item 2 <input type="text" name="item_name[1]" required>  <input type="checkbox" name="item_checked[1]" value="yes"> <br />
Enter name for item 3 <input type="text" name="item_name[2]" required>  <input type="checkbox" name="item_checked[2]" value="yes"> <br />

Now in js

$(".addCF").click(function(){
    index= $("#products [name^='item_name']").length
    $("#products").append('<tr><td>Enter name for item <input type="text" name="item_name['+index+']"> <input type="checkbox" name="item_checked['+index+']" value="yes"> <a href="javascript:void(0);" class="remCF tip" title="Remove this item">Remove</a></td></tr>');
});

Your form items will get submitted in a similar way as it currently does. But in this case you will not get an index mismatch :)

Upvotes: -1

Give the checkboxes different name attributes or else you won't be able to tell the difference between them w/o using Javascript (which you didn't tag) and then see if array key is present when the form is submitted:

$checkbox_map = array();
foreach($_POST as $key=>$value) {

    if (strpos($key, "item_checked") === 0) $checkbox_map[$key] = 1;

}

If using this method you can remove the array notation [] in the name attribute for the checkboxes.

Upvotes: 0

Related Questions