I have a simple form with two text boxes: One for peoples "name" and the other for their "surname". On the page you can click and it will add two more text boxes below, also for "name" and "surname".. so basically you could add as many pairs of name and surname as you want.
How do I count how many pairs/rows (of "names" and "surnames") of inputs?
You can see the demo here: http://poostudios.com/jstest2.html
Here's the code:
<html>
<head>
<script type="text/javascript" src="nutrition/jquery-3.1.1.js"></script>
<style type="text/css">
div{
padding:8px;
}
</style>enter code here
</head>
<body>
<form action="results.php" method="get">
<script type="text/javascript">
$(document).ready(function(){
var counter = 2;
$("#addButton").click(function () {
var newTextBoxDiv = $(document.createElement('div'))
.attr("id", 'TextBoxDiv' + counter);
newTextBoxDiv.after().html('<label>Name : </label>' +
'<input type="text" name="textbox' + counter +
'" id="textbox' + counter + '" value="" ><label> Surname : </label>' +
'<input type="text" name="textbox' + counter +
'" id="textbox' + counter + '" value="" >');
newTextBoxDiv.appendTo("#TextBoxesGroup");
counter++;
});
$("#removeButton").click(function () {
counter--;
$("#TextBoxDiv" + counter).remove();
});
});
</script>
<div id='TextBoxesGroup'>
<div id="TextBoxDiv1">
<label>Name : </label><input type='textbox' id='textbox1' >
<label>Surname : </label> <input type='textbox' id='textbox2' >
</div>
</div>
<input type='button' value='Add' id='addButton'>
<input type='button' value='Remove' id='removeButton'>
<input type="submit" value="Go">
</form>
</body>
</html>
There are dozens of ways to do this. #Tibrogargan and I have littered the comments on your question with various snippets which will return the number of elements at any given time.
However, each time you want to check the count, you'd need to call those methods in full to get a 'live' count — so if you're just planning to check the number of inputs once, i.e. when the form is submitted, for example, all you need do is, in your submit handler, check the count or store the count in a variable:
$('form').on('submit',function(e){
e.preventDefault();
// store the current count in a variable (this will not change if the user adds another input)
var current_count = $('#TextBoxesGroup input').length / 2;
// do what you want with the current_count variable
console.log("The user has submitted the form with " + current_count + " input fields");
});
However, perhaps you're not only planning to count the number of input fields once. Perhaps you're monitoring the user's behaviour. In such a case, you could define a function to make things a bit less verbose.
Instead of using a counter which you increment/decrement, just define a counter function in the following way:
function counter(){
return $('#TextBoxesGroup input').length / 2;
/*
This could also be:
return document.getElementById('TextBoxesGroup').getElementsByTagName('input').length / 2;
*/
}
Now, whenever you need to check how many input pairs there are, just call counter() and the value will be returned. So, let's imagine you're checking the number of inputs when the user clicks something — your code might look like this:
$('body').on('click', 'input[type=button]', function(){
// conditionally pass the current count straight to a function which uses the data
if ( counter() > 0 ) processMyData( counter() );
// or, if you process the data here, then pass it on to another function
// store the current count
var current_count = counter();
// do nothing if there are no input fields
if ( current_count < 1 ) return;
// do what you want with the count now that you have it
myAnalytics.inputs.save( current_count );
// do something else with it
processMyData( current_count );
// etc.
});
Since you are using jquery already, this is how you are going to get the length. Divide by 2 since each you have a set of name and username.
<script>
var len = $('#TextBoxesGroup').find('input').length / 2;
// Do whatever you wanted to do with the len
</script>
Here is the plunker sample
Firstly in your code, the ids are not unique so I modified it a bit just see the demo below ( I used the append() function for your markup creation ).
Secondly since you used a counter variable just use it to count the number of pairs by dividing it with 2 (counter / 2).
var counter = 2;
$("#addButton").click(function() {
$('<div>', {
id : 'TextBoxDiv' + counter
}).append(
$('<label>', {
text: 'Name : '
}),
$('<input>', {
type: 'text',
name: 'textbox' + (++counter), // increment counter for name
id: 'textbox' + counter,
value: ''
}),
$('<label>', {
text: 'Surname : '
}),
$('<input>', {
type: 'text',
name: 'textbox' + (++counter), // increment counter for surname
id: 'textbox' + counter,
value: ''
})
).appendTo('#TextBoxesGroup');
// just divide the counter by 2 to get the pairs
console.log('input text pairs: ' + counter/2);
});
$("#removeButton").click(function() {
// if counter === 2 (initial) then remove nothing
if (counter === 2) {
return false;
}
// decrement counter by 2
// and remove the textbox container
counter-=2;
$("#TextBoxDiv" + counter).remove();
console.log('input text pairs: ' + counter/2);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="results.php" method="get">
<div id='TextBoxesGroup'>
<div id="TextBoxDiv1">
<label>Name : </label>
<input type='textbox' id='textbox1'>
<label>Surname : </label>
<input type='textbox' id='textbox2'>
</div>
</div>
<input type='button' value='Add' id='addButton'>
<input type='button' value='Remove' id='removeButton'>
<input type="submit" value="Go">
</form>
$("#textbox1").length will give you the count of occurrences of name text field.
Related
I have a simple Javascript that adds text boxes to a form. It appears to work (i.e. a new box is added to the form) but when I submit the new form elements are not added to the array. So only the info in the first text box is submitted. Here is the code.
HTML
<div id="dynamicInput">
Part SKU 1: <input type="text" name="myInputs[]">
</div>
<input type="button" value="Add Another Part" onClick="addInput('dynamicInput');">
JS
var counter = 1;
var limit = 5;
function addInput(divName){
if (counter == limit) {
alert("You have reached the limit of adding " + counter + " inputs");
}
else {
var newdiv = document.createElement('div');
newdiv.innerHTML = "Part " + (counter + 1) + " <br><input id='input"+(counter + 1)+"' type='text' name='myInputs[]'>";
document.getElementById(divName).appendChild(newdiv);
counter++;
}
}
Any help would be appreciated.
Your input name must be unique otherwise it will grab the first one and leave out the rest similar to how JS treats ID's
I have 5 textboxes displayed, a user can add more textboxes dynamically. However, I am not able to get the the sum and average of the values inputted by users on those textboxes. Can you please help me. I will really appreciate it.
Hear is the HTML code:
<html>
<head>
<title> Grading System </title>
</head>
<script src="addInput.js" language="Javascript" type="text/javascript">
</script>
<body>
<center> GRADING SYSTEM <br><br>
<form method="POST">
<div id="dynamicInput">
Subject number 1<br><input type="text" name="myInputs[]"><br>
Subject number 2<br><input type="text" name="myInputs[]"><br>
Subject number 3<br><input type="text" name="myInputs[]"><br>
Subject number 4<br><input type="text" name="myInputs[]"><br>
Subject number 5<br><input type="text" name="myInputs[]">
</div>
<input type="button" value="Add a subject" onClick="addInput('dynamicInput');">
<input type="button" name="BtnCompute" onClick="avg('dynamicInput');" value="Compute Average">
</form>
</body>
</html>
Then here's the Javascript code:
var counter = 5;
var limit = 10;
var sum=0;
var average=0;
function addInput(divName){
if (counter == limit) {
alert("You have reached the limit of adding " + counter + " inputs");
}
else {
var newdiv = document.createElement('div');
newdiv.innerHTML = "Subject number " + (counter + 1) + " <br><input type='text' name='myInputs[]' >";
document.getElementById(divName).appendChild(newdiv);
counter++
}
}
function avg(divName){
sum += document.getElementsByName("myInputs[]")[0].value;
average = sum / counter
alert("Average is " + average);
return false;
}
The problems with your original function:
function avg(divName) {
// you only look at one <input> element ever time, rather
// than iterating over the collection returned by
// 'document.getElementsByName("myInputs[]")'; plus you're using
// a global value which is (at least potentially) exposed to
// every other function, which makes it vulnerable to being
// over-written by other values; also: you're not ensuring that
// the entered-value is a Number (an <input> returns its value as
// a String, not a Number):
sum += document.getElementsByName("myInputs[]")[0].value;
// here you're working out the average of two global values,
// both of which could be corrupted by other functions, and
// neither of which - being global - are guaranteed to be
// Numbers, since you're not enforcing that anywhere. Also
// you've exposed yourself to potential browser interference
// by not ending the line with the (optional) semi-colon:
average = sum / counter
// this is personal, but for debugging I'd recommend use of
// console.log() (but, again, a purely personal reccomendation
// and not really a 'problem' as such):
alert("Average is " + average);
return false;
}
My correction of your original function would be:
function avg() {
// rather than passing in an argument explicitly, I've opted
// to use a custom data-* attribute to contain the id of the
// relevant <div> (see the HTML below, this simplifies
// changes somewhat in the future):
var div = document.getElementById(this.dataset.divname),
// using Node.querySelectorAll() to retrieve the relevant
// <input> elements (my inclination would be to further
// amend the selector to 'input,' but that depends on
// whether or not you'd have any irrelevant <input>
// elements contained within the same <div>):
inputs = div.querySelectorAll('input[type=text][name="myInputs[]"]'),
// using Function.prototype.call() to apply the
// Array.prototoype.map() function to the Array-like
// NodeList returned by document.querySelectorAll(),
// and returns an Array of (in this case) entered values:
sum = Array.prototype.map.call(inputs, function (inputNode) {
// here we convert the existing value of the <input>
// element-node to a Number (<input> elements return
// their values as a String) or, if the value can't
// be converted to a Number, or the <input> has no
// entered value, we return 0:
return parseFloat(inputNode.value) || 0;
// using Array.prototype.reduce() to sum the
// Array of values returned by Array.prototype.map():
}).reduce(function (a, b) {
// here we return the sum of the previous number
// and the current number:
return a + b;
// the 0 here is the initial starting value
// to which the numbers are added:
}, 0),
// ensuring that the counter variable (first
// argument) is parsed into an integer value
// (using parseInt(), in base-10 (the second
// argument):
average = sum / parseInt(counter, 10);
console.log("Average is " + average);
return false;
}
// here we use JavaScript to attach the event-handling function to
// the relevant <input> (I added the 'id' to enable this), and
// this binds the avg() function to handle the 'click' event:
document.getElementById('btnCompute').addEventListener('click', avg);
The HTML for the amended <input> element:
<input id="btnCompute" data-divname="dynamicInput" type="button" name="BtnCompute" value="Compute Average" />
var counter = 5;
var limit = 10;
function addInput() {
// note that I've amended this function also, to
// use the 'data-divname' attribute to hold the
// 'id' of the relevant <div>:
var div = document.getElementById(this.dataset.divname);
if (counter == limit) {
alert("You have reached the limit of adding " + counter + " inputs");
} else {
var newdiv = document.createElement('div');
newdiv.innerHTML = "Subject number " + (counter + 1) + " <br><input type='text' name='myInputs[]' >";
div.appendChild(newdiv);
counter++
}
}
function avg() {
var div = document.getElementById(this.dataset.divname),
inputs = div.querySelectorAll('input[type=text][name="myInputs[]"]'),
sum = Array.prototype.map.call(inputs, function(inputNode) {
return parseFloat(inputNode.value) || 0;
}).reduce(function(a, b) {
return a + b;
}, 0),
average = sum / parseInt(counter, 10);
snippet.log("Average is " + average);
return false;
}
document.getElementById('addNew').addEventListener('click', addInput);
document.getElementById('btnCompute').addEventListener('click', avg);
label,
input[type=text] {
display: block;
}
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<!--
Note that I've also amended your HTML, removing the
unnecessary <br /> elements, instead using CSS to
provide line-breaks; and also wrapping the <input>
elements in <labels>, both to enable the CSS line-
breaks and to enable clicks on the text to focus
the associated (nested) <input> element:
-->
<form method="POST" action="#">
<div id="dynamicInput">
<label>Subject number 1
<input type="text" name="myInputs[]" />
</label>
<label>Subject number 2
<input type="text" name="myInputs[]" />
</label>
<label>Subject number 3
<input type="text" name="myInputs[]" />
</label>
<label>Subject number 4
<input type="text" name="myInputs[]" />
</label>
<label>Subject number 5
<input type="text" name="myInputs[]" />
</label>
</div>
<input id="addNew" data-divname="dynamicInput" type="button" value="Add a subject" />
<input id="btnCompute" data-divname="dynamicInput" type="button" name="BtnCompute" value="Compute Average" />
External JS Fiddle demo, for experimentation/development.
Despite my correction of your function though, I'd probably take an alternative approach:
// because I retrieve the number of elements in a couple
// of places, I created a simple function to retrieve
// that number of elements:
function currentlyExisting(selector) {
return document.querySelectorAll(selector).length;
}
// rewritten in my own style (though this is irrelevant to the
// the question you asked):
function addNew() {
// still using the value of the custom 'data-divname'
// attribute:
var parent = document.getElementById(this.dataset.divname),
// rather than creating a HTML string, here I create nodes
// using document.createElement() and a textNode, using
// document.createTextNode():
label = document.createElement('label'),
input = document.createElement('input'),
// getting the number of currently-existing <input>
// elements using the above function, passing the
// selector as an argument:
current = currentlyExisting('input[name="myInputs[]"'),
limit = 10;
// if the current number of <input> elements is less than
// the limit:
if (current < limit) {
// we set the type of the created <input>:
input.type = 'text';
// and the name property:
input.name = 'myInputs[]';
// appending a textNode to the created <label> element:
label.appendChild(document.createTextNode('Subject number ' + (current + 1) + ':' ));
// appending the created <input> to the created <label>:
label.appendChild(input);
// attaching the created <label>, along with its own
// childNodes, to the parent div (retrieved and cached above):
parent.appendChild(label);
// setting the disabled property to true if the updated
// number of <input> elements is equal to, or greater than,
// the limit; or to false if the number of <input> elements
// remains less than the limit (preventing the addition of
// more <input> elements than that identified by the limit):
this.disabled = currentlyExisting('input[name="myInputs[]"') >= limit;
}
// all functions return a value, whether it's explicitly defined
// or undefined (as this one will), the return false of your
// original function can be added here instead if you prefer,
// but I - personally - feel it's unnecessary, so I left it out.
}
function average() {
// retrieving the relevant <div> element using the
// data-divname attribute once again:
var parent = document.getElementById(this.dataset.divname),
// retrieving the relevant <input> elements:
inputs = parent.querySelectorAll('input[name="myInputs[]"]'),
// creating an Array of the values of the relevant
// <input> elements, using Function.prototype.call()
// in order to use Array.prototype.map() on the
// Array-like NodeList returned by querySelectorAll():
values = Array.prototype.map.call(inputs, function (input) {
// returning the value of the current <input>
// element as a number to the array, using
// parseFloat() to convert that String to a
// Number; or returning 0 if the String cannot
// be parsed as a Number:
return parseFloat(input.value) || 0;
// using Array.prototype.reduce() to reduce the Array
// of numeric values (provided by map()) to a single
// number, the sum of the values:
}).reduce(function (a, b) {
// adding the previous and current values
// together:
return a + b;
// here the 0 is the initial value before the Array
// 'reduction' takes place:
}, 0),
average = sum / inputs.length;
// adding the values to the appropriate elements on screen
// for easier visualisation (and in a manner that persists):
document.getElementById('average').textContent = average;
document.getElementById('sum').textContent = sum;
document.getElementById('total').textContent = inputs.length;
}
// adding the click event handlers to the relevant button <input>
// elements using EventTarget.addEventListener():
document.getElementById('addNew').addEventListener('click', addNew);
document.getElementById('btnCompute').addEventListener('click', average);
function currentlyExisting(selector) {
return document.querySelectorAll(selector).length;
}
function addNew() {
var parent = document.getElementById(this.dataset.divname),
label = document.createElement('label'),
input = document.createElement('input'),
current = currentlyExisting('input[name="myInputs[]"'),
limit = 10;
if (current < limit) {
input.type = 'text';
input.name = 'myInputs[]';
label.appendChild(document.createTextNode('Subject number ' + (current + 1) + ':'));
label.appendChild(input);
parent.appendChild(label);
this.disabled = currentlyExisting('input[name="myInputs[]"') >= limit;
}
}
function average() {
var parent = document.getElementById('dynamicInput'),
inputs = parent.querySelectorAll('input[name="myInputs[]"]'),
sum = Array.prototype.map.call(inputs, function(input) {
return parseFloat(input.value) || 0;
}).reduce(function(a, b) {
return a + b;
}, 0),
average = sum / inputs.length;
document.getElementById('average').textContent = average;
document.getElementById('sum').textContent = sum;
document.getElementById('total').textContent = inputs.length;
}
document.getElementById('addNew').addEventListener('click', addNew);
document.getElementById('btnCompute').addEventListener('click', average);
label,
input[type=text] {
display: block;
}
#average::before {
content: 'Average: ';
}
#sum::before {
content: ', sum: ';
}
#total::before {
content: ', of: ';
}
#total::after {
content: ' entries.'
}
#total:empty::before,
#total:empty::after,
#sum:empty::before,
#average:empty::before {
content: '';
display: none;
}
<div id="results">
<span id="average"></span>
<span id="sum"></span>
<span id="total"></span>
</div>
<form method="POST" action="#">
<div id="dynamicInput">
<label>Subject number 1:
<input type="text" name="myInputs[]" />
</label>
<label>Subject number 2:
<input type="text" name="myInputs[]" />
</label>
<label>Subject number 3:
<input type="text" name="myInputs[]" />
</label>
<label>Subject number 4:
<input type="text" name="myInputs[]" />
</label>
<label>Subject number 5:
<input type="text" name="myInputs[]" />
</label>
</div>
<input id="addNew" data-divname="dynamicInput" type="button" value="Add a subject" />
<input id="btnCompute" data-divname="dynamicInput" type="button" name="BtnCompute" value="Compute Average" />
</form>
External JS Fiddle demo, for experimentation/development.
References
HTML:
Custom data-* attributes.
JavaScript:
Array.prototype.map().
Array.prototype.reduce().
document.getElementById().
document.getElementsByName().
document.querySelectorAll().
EventTarget.addEventListener().
Function.prototype.call().
HTMLElement.dataset.
parseFloat().
parseInt().
So I think you're missing a few things.
sum += document.getElementsByName("myInputs[]")[0].value;
this line gets only the first input field value, so you need a loop through all the input fields to get the actual sum
for (var i = 0; i < counter; i++)
sum += parseInt(document.getElementsByName("myInputs[]")[i].value);
Next, notice the addition of the parseInt(); method. This converts the input value (which javascript sees as a string by default) into an integer in which you can perform calculations on.
Hope that helps you, cheers
I'm having a problem here in mounting a query string with the variables that I need.
I have the following part of the code:
echo "<form class='additionals'>";
foreach($connection->query($sql2) as $additional)
{
echo "
<input class='additional-checkbox' type='checkbox' name='additional_id' value='{$additional['additional_id']}'/>{$additional['additional_name']} - ${$additional['additional_price']} <input type='number' name='additional_quantity' value='1' min='1' max='5'/><br/>
";
}
echo "</form>";
In this code snippet I get the values from database and insert each of them into a checkbox.
To get the values of the selected checkboxes I'm using jQuery:
$(document).ready(function()
{
$('.add').on('submit', function()
{
var product_id = $(this).closest('tr').find('.product-id').text();
var product_name = $(this).closest('tr').find('.product-name').text();
var quantity = $(this).closest('tr').find('input').val();
if ($(this).closest('tr').find('input.additional-checkbox').is(':checked'))
{
var additionals = $(this).closest('tr').find( '.additionals' ).serialize();
window.location.href = "add_to_cart.php?product_id=" + product_id + "&product_name=" + product_name + "&quantity=" + quantity + "&" + additionals;
}
else
{
window.location.href = "add_to_cart.php?product_id=" + product_id + "&product_name=" + product_name + "&quantity=" + quantity;
}
return false;
});
});
Let's assume that only the checkbox with value 1 is selected and the input in front related to their quantity value is 3. My output should be something like:
add_to_cart.php?product_id=4&product_name=Pizza&quantity=1&additional_id=1&additional_quantity=3
Here is my little problem. I have part of the output as I want, but the values of the other quantity inputs are also inserted to serialize. By this way the output is like:
add_to_cart.php?product_id=4&product_name=Pizza&quantity=1&additional_id=1&additional_quantity=3&additional_quantity=1&additional_quantity=1
How to make only the quantity of inputs relating to the selected checkboxes appear in the Query String? How to relate the inputs of checkboxes with the quantity inputs?
It looks like
var additionals = $(this).closest('tr').find('.additionals')
returns multiple forms. Is it possible, that in single TR you have more than one such form?
Try this
<input name="quantity_id" type="checkbox" data-quantity-input="quantity">
<input name="quantity" type="input" value="">
// get the data-quantity-input
var qtyInput = $(this).data('quantity-input');
// find the corresponding value if checkbox is checked
find('input[name='"+ qtyInput +'"]').val();
"data" attribute should be unique. You can use the index inside "for" loop.
Is there any ways to populate all of the input from certain form?
let say, some thing like this:
<form id="unique00">
<input type="text" name="whatever" id="whatever" value="whatever" />
<div>
<input type="checkbox" name="whatever" id="whatever" value="whatever" />
</div>
<table><tr><td>
<input type="hidden" name="whatever" id="whatever" value="whatever" />
<input type="submit" value="qweqsac" />
</td></tr></table>
</form>
<form id="unique01">
<div>
<input type="text" name="whatever" id="whatever" value="whatever" />
<input type="checkbox" name="whatever" id="whatever" value="whatever" />
</div>
<table><tr><td>
<input type="hidden" name="whatever" id="whatever" value="whatever" />
</td></tr></table>
<select>blah...</select>
<input type="submit" value="qweqsac" />
</form>
etc forms... forms...
*note: each form might have a different amount of input and type and also different html structure
so is there any way to populate the input from certain form id? eg if i click submit button from certain form id, then jquery will populate for me all of the input within those form id.
currently what i'm doing is like this:
$("form").submit(function(){ return validateForm($(this)) });
function validateForm(form){
var retVal = true;
var re;
$.each(form.serializeArray(), function(i, field) {
var input = $('input[name='+field.name+']');
field.value = $.trim(field.value);
switch(field.name){
case "name" :
and another cases...
}
})
}
that was work,
but in that case, i only get the field.name and field.value, and actually what i want is, i want a jquery object for each input element, so i can access their css, id, name, and even animate those input element
is there any way for this?
please let me know and thank you in advance!
AnD
To iterate through all the inputs in a form you can do this:
$("form#formID :input").each(function(){
var input = $(this); // This is the jquery object of the input, do what you will
});
This uses the jquery :input selector to get ALL types of inputs, if you just want text you can do :
$("form#formID input[type=text]")//...
etc.
The below code helps to get the details of elements from the specific form with the form id,
$('#formId input, #formId select').each(
function(index){
var input = $(this);
alert('Type: ' + input.attr('type') + 'Name: ' + input.attr('name') + 'Value: ' + input.val());
}
);
The below code helps to get the details of elements from all the forms which are place in the loading page,
$('form input, form select').each(
function(index){
var input = $(this);
alert('Type: ' + input.attr('type') + 'Name: ' + input.attr('name') + 'Value: ' + input.val());
}
);
The below code helps to get the details of elements which are place in the loading page even when the element is not place inside the tag,
$('input, select').each(
function(index){
var input = $(this);
alert('Type: ' + input.attr('type') + 'Name: ' + input.attr('name') + 'Value: ' + input.val());
}
);
NOTE: We add the more element tag name what we need in the object list like as below,
Example: to get name of attribute "textarea",
$('input, select, textarea').each(
function(index){
var input = $(this);
alert('Type: ' + input.attr('type') + 'Name: ' + input.attr('name') + 'Value: ' + input.val());
}
);
Use HTML Form "elements" attribute:
$.each($("form").elements, function(){
console.log($(this));
});
Now it's not necessary to provide such names as "input, textarea, select ..." etc.
$(document).on("submit","form",function(e){
//e.preventDefault();
$form = $(this);
$i = 0;
$("form input[required],form select[required]").each(function(){
if ($(this).val().trim() == ''){
$(this).css('border-color', 'red');
$i++;
}else{
$(this).css('border-color', '');
}
})
if($i != 0) e.preventDefault();
});
$(document).on("change","input[required]",function(e){
if ($(this).val().trim() == '')
$(this).css('border-color', 'red');
else
$(this).css('border-color', '');
});
$(document).on("change","select[required]",function(e){
if ($(this).val().trim() == '')
$(this).css('border-color', 'red');
else
$(this).css('border-color', '');
});
Sorry about the cryptic title, it's hard to describe!
I am using the following script to add a row to my form when a button is clicked:
$(document).ready(function() {
$('#btnAdd').click(function() {
var num = $('.clonedInput').length;
var newNum = new Number(num + 1);
var newElem = $('#input' + num).clone().attr('id', 'input' + newNum);
newElem.children(':first').attr('id', 'name' + newNum).attr('name', 'name' + newNum);
$('#input' + num).after(newElem);
$('#btnDel').attr('disabled','');
if (newNum == 5)
$('#btnAdd').attr('disabled','disabled');
});
$('#btnDel').click(function() {
var num = $('.clonedInput').length;
$('#input' + num).remove();
$('#btnAdd').attr('disabled','');
if (num-1 == 1)
$('#btnDel').attr('disabled','disabled');
});
$('#btnDel').attr('disabled','disabled');
});
This works absolutely fine, but it's not very user-friendly that you can only delete the last added row. Say I want to delete a row added earlier on, I would have to delete everything I'd done since then.
How can I delete any row, and at the same time reassign the count value to the other rows, so that the count is still sequential (i.e. Row1, Row2, Row3 etc, rather than Row1, Row5, Row8)?
I recommend that you don't explicitly set an id to the elements. Instead you can use jQuery powerful selectors to get the position of an element.
This is an example, based on a common html structure. Post your own html to give you a more details.
$('.btnDel').click(function() {
var num = $(this).parent().prevAll().size();
// this points to delete link.
// The previous element is the content element
$(this).prev().remove();
$('#btnAdd').attr('disabled','');
if (num-1 == 1)
$(this).attr('disabled','disabled');
});
<div class='elem'>
<span class='content'>....</span>
<a class='btnDel' href='#'>Delete</a>
</div>
Why are you even adding IDs to the rows? Remember that 83% of jQuery is "Query" - use the selectors to get to the elements you want.
I had to do a similar thing a while ago
Essentially I got the number of the deleted row ie. Row3 and then looped through the remaining rows updating their values. so Row4 becomes Row3 etc.
I used something like this
var last_val = //get the last value of the rows so you know when to stop
//knock off the Row part of the id and parses as an integer
var pos = parseFloat(row_id.slice(3))
var next_val = position+1;
var prev_val = position;
while(next_val<=last_val){
next_selector = "#Row"+next_val;
prev_id = "Row"+prev_val;
$(next_selector).attr("id",prev_id);
next_val++;
prev_val++;
}
There may be a better way to do this, but this worked for me for a cms allowing pages to be deleted from the middle of a list which then updated the row numbering.
I posted a demo here (it doesn't look good in IE because of the float, but I just wanted to post this as an example to help). I don't know how you handle gathering your form data, so I did include renumbering the cloned input IDs.
CSS
form { width: 400px; margin: 0 auto; line-height: 30px; }
input { float: right; }
HTML
<form>
<div class="main">
Name: <input type="text" /><br>
Title: <input type="text" /><br>
Company: <input type="text" /><br>
Location: <input type="text" /><br>
</div>
Additional information: <input id="btnAdd" type="button" value="Add More"/>
<div id="addFields"></div>
</form>
Script
$(document).ready(function(){
$('#btnAdd').click(function(){
// inputs reversed because of the float right
var newInput = '<div class="clonedInput">Additional Field <span></span>: ' +
'<input type="button" class="btnDel" title="Delete this field" value="X"><input type="text" /></div>';
$(newInput).appendTo('#addFields');
// disable add button if there are 5 additional fields
if ($('.clonedInput').length == 5) {
$('#btnAdd').attr('disabled','disabled');
}
renumber();
})
// Delete input field
$('.btnDel').live('click',function(){
$('#btnAdd').attr('disabled','');
$(this).parent().remove();
renumber();
})
})
// This function adds the additional field number and ID for each clonedInput field
function renumber(){
$('.clonedInput').each(function(i){
$(this).find('span').html('#' + (i+1));
// the code below will change the ID of the input, in case you collect your data based on the ID.
$(this).find('input[type=text]').attr('id', 'input' + (i+1));
})
}