Map dynamic array of checkboxes without index - php

This question builds further on the question asked here: How to map dynamic array of input fields .
I have a dynamic set of rows with each it's own input fields. These rows can be dynamically added to the DOM, so I have to use input arrays without an index ( eg fieldname[] instead of fieldname[1] etc).
The problem occurs when I use checkboxes in these rows. Since checkboxes are not submitted when they are not checked, I see no way of knowing which submitted checkbox belongs to which row values.
Example of my form:
<form>
<div class="row">
<input type="text" name="product[]">
<input type="text" name="qty[]">
<input type="checkbox" name="projectline[]">
</div>
<div class="row">
<input type="text" name="product[]">
<input type="text" name="qty[]">
<input type="checkbox" name="projectline[]">
</div>
<div class="row">
<input type="text" name="product[]">
<input type="text" name="qty[]">
<input type="checkbox" name="projectline[]">
</div>
</form>
I found an answer to a similar problem here: php array of checkboxes , but the answer obviously only applies to arrays with an index.
What is the best approach here?
EDIT :
I also check the form for errors server-side and redirect it back if it is faulty, So I need to be able to 'reconstruct' the form based on the submitted values.

One trick I've seen used for this is to put a hidden field before each checkbox that submits the same field with a value of 0. That way, if you check the checkbox it will overwrite the 0 value with the checkbox value, but if you don't, you'll get a 0 for unchecked instead of nothing in your data.
The answer from the comments of keeping a running total of indexes could work, too, but is a bit more complicated depending on how and when the DOM can be modified.

I ended up assigning an index number to each of the rows, generating a new random id each time a row is added. I used jQuery for the clone functions and event binding.
Below is my complete solution.
This is my original form:
<form>
<div class="row">
<input type="text" name="product[0]">
<input type="text" name="qty[0]">
<input type="checkbox" name="projectline[0]">
</div>
</form>
I have a template row that I use to make clones of:
<div id="templaterow">
<input type="text" name="product[%%index%%]">
<input type="text" name="qty[%%index%%]">
<input type="checkbox" name="projectline[%%index%%]">
</div>
A button to clone the row:
<button id="addrow" value="add new row"/>
And a function bound to the button:
$('#addrow').on('click',function()
{
//template row is cloned and given the right attributes:
var clone = $('#templaterow').clone(true, true);
$('.row').last().after(clone);
clone.addClass('row').removeAttr('id');
// the %%index%% placeholder is replaced by a random index number between 100 and 9999999
clone.html(function (index, html) {
var rndIndex = Math.floor((Math.random() * 9999999) + 100);
return html.replace(new RegExp('%%index%%','g'),rndIndex);
});
});

Related

inputs in form created with foreach in PHP, how to pass all input values with post method?

I created a form, where my inputs are created by a foreach loop with data coming from a mysql database.
When the form is submitted with method post, I want to be able to receive all the info through $_POST, but currently I'm only receiving the info from the last created input in the foreach loop.
The variable $fishes comes from mysql database and contains 8 rows, so the foreach loops 8 times.
My goal is to insert this data in a database table, so I can recall it.
When i run my XDebug after pressing submit, my $_POST contains action: insertFish and quantity: (value from input of last iteration in foreach).
I would also like to be able to see the label with the corresponding quantity. I thought by adding a label would work but it didn't.
My form:
<form class="fishadd__form" action="index.php?page=fishtanks&id= <?php echo $_SESSION['tank_id']; ?>" method="post">
<input type="hidden" name="action" value="insertFish">
<div class="fishadd__box--wrapper">
<?php foreach($fishes as $fish): ?>
<div class="fishadd__box">
<h2 class="fish__name"><?php echo $fish ['name']?></h2>
<img class="fish__picture" src="../src/assets/img/goldfish.svg" alt="Goldfish" width="125">
<div class="item__counter">
<div class="fishadd__bottom">
<button class="minus__button">-</button>
<label for="quantity" name="<?php echo $fish['name']?>">
<input class="fishadd__input" type="number" name="quantity" min="0" value="0">
</label>
<button class="plus__button">+</button>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<button type="submit" class="add__fish" value="submit">add to tank</button>
</form>
Thanks to the comments, unique names for the input fields was the fix. I solved it with an array that is looped inside the foreach:
<input class="fishadd__input" type="number" name="<?php echo $fish['name']?>" min="0" value="0">

Multiple Form Send With Checkbox

Is it possible, for example, if I choose more than 1 checkbox it will submite multiple forms with the other camps that I have but the only thing that will change is the value of the checkbox.
I will give a more detailed example.
I have 2 camps, 1 with the name and the other with the email and the other is those checkbox. And If I choose 2 checkbox it will submit the forum 2 times with the same name and the same email but one will be with 1 value and the other will be with the other value that I selected.
<div class="form-group">
<label>Test</label>
<div class="custom-control custom-radio">
<input type="checkbox" id="0" name="server" class="custom-control-input">
<label class="custom-control-label" for="0">Everywhere</label>
</div>
<div class="custom-control custom-radio">
<input value="1" type="checkbox" name="server" id="test" class="custom-control-input">
<label class="custom-control-label" for="teste" value="1">test</label>
</div>
<div class="custom-control custom-radio">
<input value="2" type="checkbox" name="server" id="test2" class="custom-control-input">
<label class="custom-control-label" for="test2" value="2">test2</label>
</div>
</div>
Thanks U all for your time, sorry if I wasn't detailed enough but just say it and I will improve it! Feel free to send me any link do study and implement in the code ;)
When using a checkbox, as long as they all share the Same name then they will be submitted as ONE value. Example:
A checkbox named Hobbies will submit an array of values checked when the form is submitted with a result that looks like [Cooking, Running, Jumping, Gaming]. All of that is 1 value, and not 4.
The input element is how many different results you want back.
The name attribute tag is identifies which response the answer belongs to.
The value attribute tag is what will be sent inside of the value, i.e. [1,2,3] or [A, B, C].
Please rephrase your question if you felt i did not meet the answer you were looking for. It was difficult to understand.
Edit after reading comment.
Your issue seem to be on your understanding of the form element, and not that on the checkbox attribute.
Please consider wrapping your inputs and form data inside a form tag. All inputs inside will be submitted as one, rather than as separate or individual. Your html structure seems to be what is causing your issue.
<form action="/action_page.php">
First name:<br>
<input type="text" value="Mickey"><br>
Last name:<br>
<input type="text" name="lastname" value="Mouse"><br><br>
<input type="checkbox" name="vehicle1" value="Bike"> I have a bike<br>
<input type="checkbox" name="vehicle2" value="Car"> I have a car
<input type="submit" value="Submit">
</form>
Everything inside that form element will be submitted as one POST, and from there, you can request the values from the [vehicle1] or [vehicle2] question.
HTML
<form id="form-id">
First name:<br>
<input type="text" value="Mickey"><br>
Last name:<br>
<input type="text" name="lastname" value="Mouse"><br><br>
<input type="checkbox" name="vehicle1" value="Bike"> I have a bike<br>
<input type="checkbox" name="vehicle2" value="Car"> I have a car
<input type="submit" value="Submit">
</form>
JAVASCRIPT
var ele1 = document.getElementById("form-id1"); //Your Form Element
var ele2 = document.getElementById("form-id2"); //Your Form Element
//Detects whenever this particular form is "submitted"
if(ele.addEventListener){ //Modern browsers
ele.addEventListener("submit", function(e){
ele1.action="yourUrl1";
ele1.submit();
ele2.action="yourUrl2";
ele2.submit();
//return false; //stops page from refreshing after submit
});
} else if(ele.attachEvent){ //Old IE
ele.attachEvent('onsubmit', function(e){
ele1.action="yourUrl1";
ele1.submit();
ele2.action="yourUrl2";
ele2.submit();
//return false; //stops page from refreshing after submit
});
}
I modified my response, but you might be better just connecting the two forms together. You can reference a form element from different parts of your html.
form
The form element that the input element is associated with (its form owner). The value of the attribute must be an id of a element in the same document. If this attribute isn't used, the element is associated with its nearest ancestor element, if any. This attribute lets you to place elements anywhere within a document, not just as descendants of form elements. An input can be associated with at most one form.
formaction
The URL that processes the data submitted by the input element, if it is a submit button or image. This attribute overrides the action attribute of the element's form owner.
References
Detect if form is submitted, using javascript
Submitting a form using javascript 1
Submitting a form using javascript 2
Form/Formaction Quote - Mozilla
Form - W3Schools
Formaction - W3Schools
Input Attributes - W3Schools

Sets of form fields have stopped passing information to the database

I have three sets of form fields that are shown and hidden by jQuery and a Select list.
They are displaying just like I want them. But now the information that was being passed to the php code from the first two sets is being lost and if the bottom set of three fields are the set used. The information is passed no problem.
Is this a case of similarly named items lower in the page erasing the information of items in the upper part of the pages?
How do I get around this?
<ul id="options">
<li>
<h2>Your guest names</h2>
<label for="GuestName">Guest:</label> <input type="text" style="width:180px;" name="GuestName" id="GuestName" /><br/>
</li>
<li>
<h2>Your guest names</h2>
<label for="GuestName">Guest:</label> <input type="text" style="width:180px;" name="GuestName" id="GuestName" /><br/>
<label for="GuestName2">Guest 2:</label> <input type="text" style="width:180px;" name="GuestName2" id="GuestName2" /><br/>
</li>
<li>
<h2>Your guest names</h2>
<label for="GuestName">Guest:</label> <input type="text" style="width:180px;" name="GuestName" id="GuestName" /><br/>
<label for="GuestName2">Guest 2:</label> <input type="text" style="width:180px;" name="GuestName2" id="GuestName2" /><br/>
<label for="GuestName3">Guest 3:</label> <input type="text" style="width:180px;" name="GuestName3" id="GuestName3" /><br/>
</li>
</ul>
<script>
$("li").hide();
$("#numberattending").change(function() {
var index = $(this).children(":selected").index();
$("#options").children().hide().eq(index).show();
});
</script>
When you hide those fields, try also disabling them. This will prevent them from being submitted with the form. You'll, of course, have to re-enable them when you show them.
Try these changes (your code commmented, replace with new code):
// $("#options").children().hide().eq(index).show();
$("#options").children().hide().find('input').prop('disabled', true);
$("#options").children().eq(index).show().find('input').prop('disabled', false);
A better way might be to make jQuery fire a 'hide' event when you call hide() and disable the inputs when that happens (and similar for show()):
// taken from http://stackoverflow.com/a/2857952/259457
var _oldhide = $.fn.hide;
$.fn.hide = function(speed, callback) {
$(this).trigger('hide');
return _oldhide.apply(this,arguments);
}
$('#options li').on('hide', function() {
$(this).find('input').prop('disabled', true);
});
Then you can keep your code the rest of your code the same, and the fields will be disabled/enabled automatically when you call show() or hide() on the li tags.
Is this a case of similarly named items lower in the page erasing the information of items in the upper part of the pages?
yes it is.. when the form is posted.. the fields in the form is posted by its name , in your case three inputs have the same name so it is replacing and only one is getting posted... one way is to give it a unique name..
or disableing all other field except the one ,so that it is not posted ..
try this
$("#numberattending").change(function() {
var index = $(this).children(":selected").index();
$("#options").find('input').prop('disabled',true);
$("#options").children().hide().eq(index).show().find('input').prop('disabled',false);
});

Clone form from database records using jQuery

This should be easy, but I am missing something.
I have the following form:
<div id="rsvp">
<form class="form-inline">
<fieldset>
<label class="control-label" for="input01" id="rsvp_label">John Smith</label>
<label class="control-label">Attending?:</label>
<label class="radio"><input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>Yes</label>
<label class="radio"><input type="radio" name="optionsRadios" id="optionsRadios2" value="option2">No</label>
<label class="control-label small" for="select01" id="meal"> Meal Selection:</label>
<select id="selectMeal" class="input-small">
<option>Chicken</option>
<option>Beef</option>
</select>
<button type="submit" class="btn btn-primary" id="btnrsvp">Save / Confirm Changes</button>
</fieldset>
</form>
</div>
I am successfully pulling out records in the database that match my query, and I have 1 -> n records. I'd like to clone this form for each record. So I can loop through the records, but am having trouble figuring out how to go about actually cloning the fieldset and then incrementing the ids so that I can attach a form action to each one. Or perhaps there's a better way to do this... ?
If the whole form uses class instead of ID for elements you can clone and re-use at will without needing to parse ID's. Track the record ID with a data attribute or a hidden input in each form.
If you have event handlers on any of the form field elements that are dependent on other fields in the form, you would simply look them up within the context of the individual form
Event handler example ( select ID changed to class):
<select class="input-small selectMeal">
<option>Chicken</option>
<option>Beef</option>
</select>
JS
$('.selectMeal').change(){
var rsvp_name= $(this).closest('.form-inline').find('.rsvp_label').text();
if( rsvp_name=='John Smith') doSomething();
})
The control would be the form tag - put a data-id="3" where 3 represents the user id for john smith. Then change all your input ids to data-id's as well, and on your form submit handler, just submit said data to whatever record maps to the <form> tag's data-id attribute.
Have a look at SheepIt, a form cloning jQuery plugin.

cloning form elements and the return a template file

I am building a website, where on the click of a link you can clone the form elements, what I am wanting to know is that, when I send the $_POST to my controller and check that the information submitted is correct, how do I then return a template that has enough elements so that errors can be rectified, so example my original form looks like this,
<fieldset class="entry">
<label for="email_address">Email Address</label>
<input type="text" name="email_address[]" value="" class="text small"/>
<label for="firstname">Firstname</label>
<input type="text" name="firstname[]" value="" class="text small"/>
<label for="surname">Surname</label> <input type="text" name="surname[]" value="" class="text small"/>
</fieldset>
how can I return the correct amound of fieldsets based on the $_POST?
To answer this:
How can I return the correct amount of fieldsets based on the $_POST?
If each fieldset only has one instance of each bracketed[] field name, you can just count how many were submitted (of any of the fields).
$number_of_fieldsets = count((array) $this->input->post('email_address'));
I've used $this->input->post() (since you're using CI) in case the value is not set (it will return false), you may use some isset() logic instead if you wish.
I've cast to array here in case the return value of $this->input->post('email_address') is false (count will return 0) or for some reason, a string (count will return 1). This is just a mild attempt at being defensive, you will probably want to handle unexpected results with your own methods.
Once again, it doesn't matter which field you choose to count.

Categories