html checkbox arrays generating additional array elements on a change - php

Long time listener, first time caller. I am implementing a system to track who participates in various events. After defining the "activity" record, the plan is to populate another table with the list of members (lets say 60) who might have attended, then present a form for the organizer to 'check' who actually participated with the hours spent. This information is then passed by POST to update the database.
The issue deals with the array of Checkboxes, one for each participant, and correct handoffs to the DB update process. The problem is that the first time a checkbox is changed, either manually by the organizer or automatically to reflect a previous choice, it generates an extra element in the checkbox array, thereby throwing them all out of alignment with the other arrays. This link (Do checkbox inputs only post data if they're checked?) was the closest to the problem that I found, but did not address handling checkbox arrays.
I implemented the hidden checkbox approach per several posts, tried both absolute array indexing, and am I still get an extra array element every time. I even contemplated replacing the checkboxes with something less elegant like 2 radio buttons (Y/N) each or a two-value select field. I am definitely not an expert here and am willing to do the research and learn, but I've hit a dead-end.
Any ideas, workarounds, or links to other references for this would be appreciated.
Here is the code:
<?php
echo "<form action=\"index.php\" method=\"post\">";
$query = ((get stuff));
$result = mysqli_query($con, $query) or die ('Sorry, could not access the joined users+activitypart tables');
// extract and format all users for the activity
$i = 0;
while($row=mysqli_fetch_array($result, MYSQL_ASSOC))
{
$firstname = $row['firstname'];
$lastname = $row['lastname'];
$apidx[] = $row['apidx']; // Pointer to this user's record
$isParticipant[] = $row['isParticipant']; // checkbox value
$actduration[] = $row['actduration']; // Actual duration in hours spent
$role[] = $row['role']; // Role that this person held during this activity
?>
<input type="hidden" name="passidx[]" value="<? print $apidx[$i] ?>">
<input type="hidden" name="passpart[<? $i ?>]" value="0" />
<input type="checkbox" name="passpart[<? $i ?>]" value="1" <? if($isParticipant["$i"]) print "CHECKED" ?> />
<input type="text" name="passdura[]" size="7" value="<? print $actduration["$i"] ?>">
<?php
echo "$i $firstname $lastname<br>";
$i++;
}
?>
<!-- when done, pass all name field values to actusr08a -->
<br><input type="hidden" name="content" value="actusr08a">
<span class="form-field-no-caption">
<input type="submit" value="Submit">
</span>
</form>
So, When I load this page with 15 members, as a debug step, I count the 3 arrays and they all show 15, 15, 15 elements each at load time. If I click on 2 check-boxes, post it to the next page and do a count of the received arrays, two of the arrays (passidx, passdura) show 15 elements each, and the checkbox array (passpart) shows 17. since 2 checkboxes changed, seems they then post the change, thus the additional 2 elements. This is what I am trying to fix.

Related

Posting checkbox with html/php values does not work in all cases

So, my webpage has a html-table which displays rows with one item pr. row including various data regarding that item in the columns.
The table is populated using mysqli call to db. So far so good.
Excerpts of the table look like this (I've tried to only show the "important" parts of the code to avoid cluttering - there 8 more text fields similar to "nytAntalGangeUdfoert" for each item)
<td><input type="text" name="nytAntalGangeUdfoert[]" value="<?php echo $antalGangeUdfoert ?>"></td>
<?php if ($aktivStatus == 1) { ?>
<td><input type="checkbox" name="nyAktivStatus[]" value="<?php echo $aktivStatus ?>" checked="checked"/></td>
<?php } else { ?>
<td><input type="checkbox" name="nyAktivStatus[]" value="<?php echo $aktivStatus ?>" /></td>
The text field(s) works fine in all aspects.
For the checkbox, the if-else part decides whether the checkbox should be displayed as checked (active or not) dependent on the value in my db-table (1 or 0) This works fine.
I then have 'duplicate' hidden fields to log the original status of the checkbox for later comparison after posting:
<td><input type="hidden" name="antalGangeUdfoert[]" value="<?php echo $antalGangeUdfoert ?>"></td>
<td><input type="hidden" name="aktivStatus[]" value="<?php echo $aktivStatus ?>"></td>
All of this is posted to another page where it is handled as follows (again, only excerpts of the full table). 'aktivstatus' is the old status from db, and 'nyaktivstatus' is the one posted (i.e. the one selected by the user via the checkboxes - can of course be the same as original state)
if(isset($_POST['submit']))
{
$antalGangeUdfoert = $_POST["antalGangeUdfoert"];
$nytAntalGangeUdfoert = $_POST["nytAntalGangeUdfoert"];
$aktivStatus = $_POST["aktivStatus"];
foreach( $navn as $n => $n )
{
if(isset($_POST["nyAktivStatus"][$n])) {
$nyAktivStatus[$n] = 1;
} else {
$nyAktivStatus[$n] = 0;
}
if( $antalGangeUdfoert[$n] <> $nytantalGangeUdfoert[$n] || $aktivStatus[$n] <> $nyAktivStatus[$n]) {
//run function to update items where a change has been made by the user)
As stated earlier, the above approach works fine for all the text fields, but in some cases, the new state of a checkbox is saved for the wrong item, apparently (changes to the text fields are correctly saved in db regardless)
Examples below:
Row---status when fetched---user input---saved as
Row1: 1-->0-->1 ERROR
Row2: 1-->1-->1 OK
Row3: 1-->1-->0 ERROR
Row1: 1-->1-->1 OK
Row2: 1-->1-->1 OK
Row3: 0-->1-->1 OK
Row1: 1-->0-->0 OK
Row2: 1-->0-->0 OK
Row3: 1-->0-->0 OK
Row1: 0-->1-->1 OK
Row2: 0-->1-->1 OK
Row3: 0-->1-->1 OK
Row1: 1-->0-->1 ERROR
Row2: 1-->0-->0 OK
Row3: 1-->1-->0 ERROR
FYI at one point, I changed the checkbox into a textfield and manually entered 1 or 0, and this worked fine...not ideal solution, though...
So, I guess there's something going wrong when posting/assigning the "nyaktivstatus' (user entered status)
Can anyone spot the issue in my code? Or spot a pattern that I'm not seeing?
Thanks!
$aktivStatus may not be set at all if the checkbox was not ticked.
Right where you have $aktivStatus = $_POST["aktivStatus"]; try replacing it with:
if (!array_key_exists('aktivStatus',$_POST))
$aktivStatus = 0;
else
$aktivStatus = $_POST["aktivStatus"];
This way if the checkbox was not set and the browser did not POST it at all, your variable will assume 0, otherwise it'll assume the value POSTed by browser.
As the unchecked checkboxes are not carried on post,in this case we might use a little javascript to take the value of checkboxes to a corresponding hidden text box on the on change event of the checkbox. here's a sample javascript to keep on the same page as my form below. This code is a demonstration on how to achieve the questioners target. Could be possible other ways to achieve this. Sessions could also be used on some parts.
<script type="text/javascript">
function changed(id){
var checkBoxValue=document.getElementById(id).value;
id=id.replace('checkbox','');
hTextBoxid='hidden['+id+']';
var hiddenTextBox=document.getElementById(hTextBoxid);
hiddenTextBox.value=checkBoxValue;
}
</script>
Here's the form
<?php
//uncomment for debugging
//if(isset($_POST)){
//for debugging could use this to see the variables that were passed on form submit
//echo '<pre>'; print_r($_POST); echo'</pre>';
//on post of data remember to sanitize and do the checks here server side.
//as we used javascript on the form for checkboxes and hidden text box should varify those post data on server side here.for example whether the check box array count and value matches..
//;}
?>
<form action="" method="post" enctype="application/x-www-form-urlencoded">
<table>
<tr>
<?php
//sample data as if it came from db
$antalGangeUdfoert=array('a','b','c','d','x','y','z');
//sample data as if it came from db
$aktivStatus=array(0,0,1,0,1,1,0);
?>
<?php
$i=0;
//could use a for loop after counting the fetched rows,
//could use other than $aktivStatus, i used $aktivStatus here
foreach($aktivStatus as $aktivStatus){
echo '<td><input type="text" name="nytAntalGangeUdfoert['.$i.']" value="'.$antalGangeUdfoert[$i].'"></td><td>';
//check whether its checked depending on activeStatus
$aktivStatus[$i] == 1? $check='1':$check="0";
//and according to check draw a check box and a hidden text for each
echo '<input type="hidden" id="hidden['.$i.']" name="nyAktivStatus['.$i.']" value="'.$check.'"/>
<input type="checkbox" id="checkbox'.$i.'" value="'.$aktivStatus[$i].'" checked="'.$check.'" onChange="changed(this.id);"/>';
$i++;
};
?>
</td></tr></table>
<input type="submit" name="sub" value="sub"/>
</form>

Adding rows to database from a dynamic form in PHP

I have a form to index parts that belong to schematic drawings. We have hundreds of drawings and each one will have a different number of parts attached to it. Each part requires three pieces of information a number, part_id and Description. The initial form captures that and allows the user to add as many rows to the form as are needed to get all the parts from the drawing. The form fields are named Number_1, Part_id_1 and Description_1. Each row added to the form increments the number at the end by one. For example if a schematic has 10 parts I will end up with Number_1 - Number_10.
while ($i <= $Fieldnum) {
$Number = "Number_".$i;
$PartNumber = "PartNumber_".$i;
$Description = "Description_".$i;
print ("
<input name=$Number type=\"text\" size=\"3\" />
<input name=$PartNumber type=\"text\" size=\"20\" />
<input name=$Description type=\"text\" size=\"35\" />
");
$i++;
}
Where I'm stuck is getting the data into the MySQL database. Each form row needs to become a row in the database. If this was a static form it would be easy, but with each form element having a dynamic name I don't know how to proceed.
Use two tables. Create a table for the schematic. Create a table for parts, and assign a foreign key with the id of the schematic.
There is a better way to do that.
Give all your inputs the same name for a given element adding [] so it ends up as an array server side.
Here is an example:
<input name='number[]' .../>
<input name='part_number[]' .../>
<input name='description[]' .../>
You can have as much of these as you want...
Then server side just iterate through them :
for($i=0; $i<count($_POST['number']); $i++){
$row = array();
$row['number'] = $_POST['number'][$i];
$row['part_number'] = $_POST['part_number'][$i];
$row['description'] = $_POST['description'][$i];
//do your mysql insert here.
}

PHP, Submitting a two dimensional table with TextBox to proccess

I am building an application which has a dynamic table, everytime you open the page table`s row and columns changes based on data in database.
Each Row is a vendor company each colomn is a Item Title. All these vendors upply the same item, So this table has a textbox in each contains a TextBox so user can type the value, which represents the amount of fruit they want from that supplier. the following is the example.
So what I need to do now is, after entering these values, I'd like to process them through PHP, and then see 4 different reports at the confirm page, example: write the Company name and under that, what they have to supply for each item, then the next company, so on and so forth to the end.
I don't know if i should create different class for each textbox? or ID them!! SHould I Array them? I am confused.. If any of you guys can help, would be wonderful
Thanks a lot
I would suggest you just name the input elements as an array. something like:
<input type="text" name="fruits[company1][apple]">
<input type="text" name="fruits[company1][berries]">
<input type="text" name="fruits[company1][orange]">
<input type="text" name="fruits[company1][bannana]">
<input type="text" name="fruits[company2][apple]">
<input type="text" name="fruits[company2][berries]">
<input type="text" name="fruits[company2][orange]">
<input type="text" name="fruits[company2][bannana]">
or the same thing with the fruit being the first level and company name being second. It is really the same thing and generally just as easy to use either one. Just depends on how you want to loop over the data once you post the form. You might be better off also using ids for the company name and/or the fruit. Just makes it so, for example, company names with a space are still valid.
Using the above form, you can process the data with something like this:
<?php
foreach($_POST['fruits'] as $company=>$row){
foreach($row as $fruit=>$quantity){
if(!is_numeric($quantity) || $quantity < 0){
$quantity = 0;
}
echo "You selected {$quantity} {$fruit} from {$company}";
}
}
I would try creating a multi dim array with the ID of the item as the first dimension. Like this:
<input type="textbox" name="textbox[<?php echo $row['item_id']; ?>]["apple"]" value="<?php echo $row['apple']; ?>" />
Then, in your processing script:
foreach ($_POST['textbox'] as $row)
{
foreach ($row as $key => $val)
{
$q = "update `items` set `apple` = {$val['apple']} where `item_id` = {$key}";
mysql_query($q);
}
}

PHP avoiding a long POST

This is more of a technique question rather than maybe code. I am having a php form with many fields (items to select). Naturally some of the items might be selected and some not. How do I know which ones are selected when i post the data from page 1 to page 2? I thought of testing each one if empty or not, but there are just too many fields and it doesn't feel at all efficient to use or code.
Thanks,
UPDATE EDIT:
I've tried the following and maybe it will get me somewhere before I carry on testing the repliers solutions...
<html>
<body>
<form name="test" id="name" action="testprocess.php" method="POST">
<input type="text" name="choices[shirt]">
<input type="text" name="choices[pants]">
<input type="text" name="choices[tie]">
<input type="text" name="choices[socks]">
<input type="submit" value="submit data" />
</form>
</body>
</html>
and then second page:
<?php
$names = $_POST['choices'];
echo "Names are: <br>";
print_r($names);
?>
This gives out the following:
Names are: Array ( [shirt] => sdjalskdjlk [pants] => lkjlkjlk [tie]
=> jlk [socks] => lkjlkjl )
Now what I am going to try to do is iterate over the array, and since the values in my case are numbers, I will just check which of the fields are > 0 given the default is 0. I hope this works...if not then I will let you know :)
I think what you're looking for is this:
<form action="submit.php" method="POST">
<input type="checkbox" name="checkboxes[]" value="this" /> This
<input type="checkbox" name="checkboxes[]" value="might" /> might
<input type="checkbox" name="checkboxes[]" value="work" /> work
<input type="submit" />
</form>
And then in submit.php, you simply write:
<?php
foreach($_POST['checkboxes'] as $value) {
echo "{$value} was checked!";
}
?>
The square brackets in the name of the checkbox elements tell PHP to put all elements with this name into the same array, in this case $_POST['checkboxes'], though you could call the checkboxes anything you like, of course.
You should post your code so we would better understand what you want to do.
But from what I understood you are making a form with check boxes. If you want to see if the check boxes are selected, you can go like this:
if(!$_POST['checkbox1'] && !$_POST['checkbox2'] && !$_POST['checkbox3'])
This looks if all the three check boxes are empty.
Just an idea:
Create a hidden input field within your form with no value. Whenever any of the forms fields is filled/selected, you add the name attribute of that field in this hidden field (Field names are saved with a comma separator).
On doing a POST, you can read this variable and only those fields present in this have been selected/filled in the form.
Hope this helps.
Try this.....
<?php
function checkvalue($val) {
if($val != "") return true;
else return false;
}
if(isset($_POST['submit'])) {
$values = array_filter(($_POST), "checkvalue");
$set_values = array_keys($values);
}
?>
In this manner you can get all the values that has been set in an array..
I'm not exactly sure to understand your intention. I assume that you have multiple form fields you'd like to part into different Web pages (e.g. a typical survey form).
If this is the case use sessions to store the different data of your forms until the "final submit button" (e.g. on the last page) has been pressed.
How do I know which ones are selected when i post the data from page 1 to page 2?
is a different question from how to avoid a large POST to PHP.
Assuming this is a table of data...
Just update everything regardless (if you've got the primary / unique keys set correctly)
Use Ajax to update individual rows as they are changed at the front end
Use Javascript to set a flag within each row when the data in that row is modified
Or store a representation of the existing data for each row as a hidden field for the row, on submission e.g.
print "<form....><table>\n";
foreach ($row as $id=>$r) {
print "<tr><td><input type='hidden' name='prev[$id]' value='"
. md5(serialize($r)) . "'>...
}
...at the receiving end...
foreach ($_POST['prev'] as $id=>$prev) {
$sent_back=array( /* the field values in the row */ );
if (md5(serialize($sent_back)) != $prev) {
// data has changed
update_record($id, $sent_back);
}
}

PHP Mysql & Jquery dynamically populating multiple records

I want to above Master and child system by using PHP,MYSQL & JQuery.
I am attaching sample image link below See screenshot
Product Quantity and UOM is field which belong to MAster Table and
Code, Component, category, quantity (Also) & UOM (duplicate) is belong to Child table.
I want to add Code, Component, category, quantity etc multiple time whenever user click on add.
Just need to know how can i save all these multiple records when someone completed their works and click on Final Save Button?
I am really and very aggressively searching for this but didn't get any anwer.
If anyone who can find the way or any help or anything that will help me towards this system.
Thanks a lots pls pls Help
you'll want to use
jQuery ajax to save data
.clone() to add a record in the UI you'll have to reset the values will your at it
that should get you started
Each time your user clicks 'add' you want to take the values of your form inputs, build a new table row and show their selected values. This is easy enough, but you also need to add hidden inputs which represent what they chose in the select boxes above, so when the user clicks save, the whole form is posted and you can process the input. A simple example would be:
<script>
var count = 0;
$('#add').click(function(event)
{
var code = $('#code').val(),
component = $('#component').val()
category = $('#category').val(),
uom = $('#uom').val();
$('#table').append(
'<tr>'
+ '<td>' + code + '<input type="hidden" name="record[' + count + '][code]"></td>'
+ '<td>' + component + '<input type="hidden" name="record[' + count + '][component]"></td>'
+ '<td>' + category + '<input type="hidden" name="record[' + count + '][category]"></td>'
+ '<td>' + uom + '<input type="hidden" name="record[' + count + '][uom]"></td>'
+ '</tr>'
);
/*
EDIT: I changed this to a DECREMENTOR so our keys don't overlap and override
anything that is CURRENTLY in the database
*/
count --;
})
</script>
This would attach a click handler to the add button. Each time it is clicked, we get the values of the inputs, store them in a variable, and build + append a new table row to your "preview table" below, which shows the values they selected and creates hidden inputs which can be processed later after the user clicks Save.
Some notes about this:
- it only gets the value of the selected inputs (so for the select boxes, the value of the option not the text. you'll have to do some extra work to replace that into your table row.
- your entire table will have to be encapsulated in a <form> tag, which your save button must also be inside.
Once you get the posted data to the server, do a print_r($_POST) to see what it looks like, you should be able to figure out how to process it fairly easily.
edit
Okay, so you asked a lot of questions here, i'll try to address them as best I can, without writing a novel.
What if someone mistakenly clicks on add and wants to cancel the addition (or changes their mind, whatever).
This actually isn't that hard. If this happens, just remove the appended table row from your table using $.remove. Since all the hidden input elements are contained within the table row, they will also be removed from the form so when the user posts, the fields will not be present.
How should you sanitize the data?
Sanitize the data when the user clicks add, as you populate the form, instead of afterwards, just before you post the form. It will be easier to deal with the input errors when the user clicks add than it will be to deal with them when they click save.
How can you use this method if you want to modify existing records in the database?
There's a few different ways you can handle this. The easiest way is to pre-populate your form with table rows for each existing row in your database, and add an id (assuming you have an auto-increment primary key for each row) input value for that record on the table row. This way when you're processing the form, you'll be able to see if it's an existing record by checking for the existence of the id in the posted data and verifying that it exists in your database. If it doesn't have an id key you know that it is a new record and you need to do an INSERT, and if it does, you can do an UPDATE or leave the record be. For DELETED rows, you'll want to loop through your POSTed data before doing any INSERTs and gather the id values that have been posted and run a query something like DELETE FROM table WHERE ID IN (<list of posted ids>). This will delete any rows that the user removed, then you can loop through the POSTed data again and insert the new rows.
An example of pre-populating this table would look something like this:
<?php
$query = "SELECT * FROM bill_items WHERE bill_id = 123";
$result = mysql_query($query);
$materials = array();
while ($row = mysql_fetch_assoc($query))
{
$materials []= $row;
}
?>
<? foreach ($materials as $material): ?>
<tr>
<td>
<?= $material['code']; ?>
<input type="hidden" name="record[<?= $material['id']; ?>][code]"
value="<?= $material['uom']; ?>">
</td>
<td>
<?= $material['component']; ?>
<input type="hidden" name="record[<?= $material['id']; ?>][component]"
value="<?= $material['uom']; ?>">
</td>
<td>
<?= $material['category'];
<input type="hidden" name="record[<?= $material['id']; ?>][category]"
value="<?= $material['uom']; ?>">
</td>
<td>
<?= $material['quantity']; ?>
<input type="hidden" name="record[<?= $material['id']; ?>][quantity]"
value="<?= $material['uom']; ?>">
</td>
<td>
<?= $material['uom']; ?>
<input type="hidden" name="record[<?= $material['id']; ?>][uom]"
value="<?= $material['uom']; ?>">
<input type="hidden" name="record[<?= material['id']; ?>][id]"
value="<?= $material['id']; ?>">
</td>
</tr>
<? endforeach; ?>
Also, a note. I changed the javascript example code above. I changed count++ to count-- because when you pre-populate the form with data that is currently in the database you are going to use the id of the material in the input key. When a user adds new data, there is a possibility that the key generated with javascript (with count++) will collide with the existing table data. To rectify this, we change it to count--. This key (in javascript) really isn't important, it's just keeping our data grouped together, so a negative value here does not affect anything.

Categories