1

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.

1
  • I thought about using a unique value* for each row, however this presents issues in other areas: in my main application, new rows are added via a button click dynamically Commented Sep 6, 2016 at 19:19

4 Answers 4

2

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

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

Comments

1

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!

Comments

0

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.

3 Comments

Not sure that this would work for me. There will be an arbitary number of user-generated rows. So I cannot possibly come up with variables for all of them. A user clicks a button and displays new row (with jquery). Appreciated, nonetheless
Sure, just number them using javascript - I'll edit my answer
Thanks, if you look at my original question, you can see how I'm adding the rows. Is there any way to add the uniqueness to each row?
-1

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 :)

1 Comment

The row removal feature that the OP has can result in your solution creating multiple rows with the same index.

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.