Reputation: 594
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
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
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
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
Reputation: 7884
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