Im trying to post a cloned section of a form but it doesnt submit all due to element names being identical.
Does anyone know the best process for changing input name attributes during a clone ?
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
if (checkMACAddress()==true) {
$("#test").clone().insertAfter("div.test-row:last");
}
});
});
function checkMACAddress() {
var valid = true;
for ( var i = 0, l = document.getElementsByName("mac").length; i < l; i++ ) {
var macAddress=document.getElementsByName("mac")[i].value;
var macAddressRegExp=/^(?:[0-9A-F]{2}[:]?){5}(?:[0-9A-F]{2}?)$/i;
if (macAddressRegExp.test(macAddress)==false) { //if match failed
alert("MAC Invalid - Must be IEEE.802 example 00:3F:00:10:00:2C");
valid=false;
}
}
return valid;
}
</script>
<h3>Account Details</h3>
<div class="row">
<div class="columns small-4">
<label>Destination Account Number*</label>
[[input||type=text||name=Account||name_literal=Account||placeholder=12345||required=required]]
</div>
</div>
<hr>
<h3>Device Details</h3>
<h5>
<button type='button'>Add Device</button>
</h5>
<div id="test" class="test-row">
<div class="columns small-3">
<label>MAC - IEEE.802 Format Only</label>
[[input||type=text||name=mac||name_literal=mac||placeholder=54781A139264||required=required]]
</div>
<div class="columns small-3">
<label>Extension/Seat Number</label>
[[input||type=text||name=seat||name_literal=seat||placeholder=200]]
</div>
<div class="columns small-3">
<label>Display Name</label>
[[input||type=text||name=station||name_literal=station||placeholder=reception desk]]
</div>
One way could be to work with an array syntax as field name, for example: data[identifier][]. Otherwise you'll need to modify the name attribute after cloning:
var c = 0;
// each time you click on the button...
$(".clone").on('click',function(){
// generate a new clone of complete test div..
var klon = $( '#test').clone();
// append it to parent element (or after existing, as you like)
$('#test').parent().append(klon);
// increase global counter...
c++;
// inside clone find all inputs
// (if you other form elements, you must add them in selector)
klon.find('input').each(function() {
var $this = $(this),
name = $this.attr('name');
// update name attribute
$this.attr('name', name + '_' + (c));
});
});
See a fiddle here.
I still prefer the name / array solution, it is easier to handle server-side, because you can loop over the fields instead of asking for unkown amount of new fields.
Related
In my HTML form, it's possible to add additional inputs dynamically by clicking a button. I've got this part to work, however I need each input to have a unique name.
This is my code so far,
<div class="control-group field_wrapper">
<label class="control-label"><strong> Phone Number 1</strong></label>
<input type="text" class="input-medium" name="phone_number[]">
<button class="btn btn-success add-number" type="button" title="Add">Add</button>
</div>
<div class="additionalNumber"></div>
My JS as below,
$(document).ready(function(){
var maxField = 10;
var addButton = $('.add-number');
var wrapper = $('.additionalNumber');
function fieldHTML(inputNumber) {
return `<div class="control-group field_wrapper">\
<label class="control-label"><strong> Phone Number ${inputNumber}</strong></label>\
<input type="text" class="input-medium" name="phone_number[${inputNumber}]">\
<button class="btn btn-danger remove" type="button">Remove</button>\
</div>`;
}
var x = 1;
$(addButton).on('click', function(e) {
if (x < maxField) {
x++;
$(wrapper).append(fieldHTML(x));
}
if (x >= maxField) {
alert('Limited to 10.');
}
});
$(wrapper).on('click', '.remove', function(e) {
e.preventDefault();
$(this).parents('.control-group').remove();
x--;
});
});
Using this code, I can get unique name for each input which are created by dynamically. But my problem is name[x] index not works properly when it is removing. That mean, just think I have added 3 input and delete second one and again I am adding new one, then it has same name twice. In this case, it is phone_number[3] for second input and phone_number[3] for thirt one also.
This is the fiddle from above code. Any help is appreciated.
You don't need to index the inputs for PHP either - 3x inputs named phone_number[] will automatically be indexed 0 - 2 on the back end:
<input type="text" name="phone_number[]">
<input type="text" name="phone_number[]">
<input type="text" name="phone_number[]">
[phone_number] => Array
(
[0] => a
[1] => b
[2] => c
)
That doesn't help with your plain text Phone Number n label though. And maybe you have your own reasons to want an input name index.
If you think about it, if you're going to allow deletions of any item in the list, and you need the results to be sequential, the only option is to renumber everything each time you make a change. You don't need to include any numbering when you add a new element, just regenerate all numbering.
Here's a working snippet doing that. My changes:
No need to pass the count x to fieldHTML(), we're going to renumber everything after you add the element;
Add a <span class='count'></span> in your label, which we can target and update;
Add a reNumber() function which will iterate over all inputs on the page and number them sequentially;
Call that function after any change;
Notes:
The 2 separate tests if (x < maxField) and if (x >= maxField) can be combined into a single if/else;
If you want to get rid of the duplication of your HTML block, you could give the first one an id like template, and then instead of duplicating that HTML in your JS, just copy the template, eg :
let $copy = $('#template').clone();
wrapper.append($copy);
wrapper and addButton are already jQuery objects, no need to wrap them with $() a second time to use them;
If you do want to number your input names, for consistency the first should probably be phone_number[1];
$(document).ready(function() {
var x = 1;
var maxField = 10;
var addButton = $('.add-number');
var wrapper = $('.additionalNumber');
function fieldHTML() {
return `<div class="control-group field_wrapper">\
<label class="control-label"><strong> Phone Number <span class='count'></span></strong></label>\
<input type="text" class="input-medium" name="phone_number[]">\
<button class="btn btn-danger remove" type="button">Remove</button>\
</div>`;
}
/**
* Iterate over all inputs and renumber sequentially
*/
function reNumber() {
let count;
wrapper.find('.field_wrapper').each(function (i) {
// .each() index is 0-based, and input #1 is already on the page,
// so extras start at #2
count = i + 2;
$('.count', $(this)).html(count);
// If you want to index your input names, but you can safely leave
// this out, PHP will index them anyway
$('input', $(this)).attr('name', 'phone_number[' + count + ']')
});
}
addButton.on('click', function(e) {
if (x < maxField) {
x++;
wrapper.append(fieldHTML());
reNumber();
} else {
alert('Limited to 10.');
}
});
wrapper.on('click', '.remove', function(e) {
e.preventDefault();
$(this).parents('.control-group').remove();
x--;
reNumber();
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="control-group field_wrapper">
<label class="control-label"><strong> Phone Number 1</strong></label>
<input type="text" class="input-medium" name="phone_number[]">
<button class="btn btn-success add-number" type="button" title="Add">Add</button>
</div>
<div class="additionalNumber"></div>
I am trying to make an e-commerce-like webpage (for practice) wherein a click on any of the buttons would update the cart value by the number (quantity) specified on the input element.
So far, I was only able to update the cart from the first form because when I try to assign the function on every form using a loop, the cart updates for a millisecond then returns to zero. I assume its because of the scope.
I know there's an easier way to do this without manually assigning the function for every document.forms[n]
JS
window.onload = function()
{
var getForm = document.forms[0];
var numItems = 0;
getForm.onsubmit = function(event)
{
event.preventDefault();
var getInput = getForm.elements["num-item"].value;
if(parseInt(getInput))
{
numItems = numItems + parseInt(getInput);
var getCart = document.getElementById("item-count");
getCart.innerHTML = numItems;
getForm.reset();
}
else
{
alert("Please enter a valid number");
}
}
HTML
Cart:
<div class="basket">
<p><i class="fa fa-shopping-basket"></i></p>
<p id="item-count">0</p>
</div>
HTML Form: For brevity, I'm only posting 1 form example, but in reality, I have 6 other forms that are exactly the same.
<div class="buy-config">
<form class="buy-form" name="buy-form">
<label>Quantity:</label>
<input type="text" class="num-item" />
<button class="buy-btn">Add to Cart</button>
</form>
</div>
Loop through all of the forms by querying the selector (using whatever method you prefer, depending on performance requirements and markup flexibility -- I've used getElementsByClassName) and executing a for loop.
Inside the loop, bind a function to the "submit" event using addEventListener. You can define the function in-line (as I've done), or define the function elsewhere, assign it to a variable, and reference the variable when binding to the event.
Within the event listener function, you will refer to the form that was submitted as this.
On top of the changes described above, I've made some minor changes to your code:
Your previous version was overwriting the contents of the cart each time. This may have been on purpose, depending on whether you have one "basket" for each item or one overall (this wasn't clear in the question). So, rather than initialize numItems to zero, I've initialized it to the current number of items in the cart.
Consider using input type="number" HTML form elements. They're supported by nearly every browser and only accept digits -- they also have up/down arrows and can be set with the scroll wheel. On browsers that don't support them, they fall back to a basic text input.
var forms = document.getElementsByClassName("buy-form");
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener("submit", function(event) {
event.preventDefault();
var numItems = parseInt(document.getElementById("item-count").innerHTML);
var getInput = this.getElementsByClassName("num-item")[0].value;
if (parseInt(getInput)) {
numItems = numItems + parseInt(getInput);
var getCart = document.getElementById("item-count");
getCart.innerHTML = numItems;
this.reset();
} else {
alert("Please enter a valid number");
}
});
}
<div class="basket">
<p><i class="fa fa-shopping-basket"></i></p>
<p id="item-count">0</p>
</div>
<div class="buy-config">
<form class="buy-form" name="buy-form">
<label>Quantity:</label>
<input type="number" class="num-item" />
<button class="buy-btn">Add to Cart</button>
</form>
</div>
<div class="buy-config">
<form class="buy-form" name="buy-form">
<label>Quantity:</label>
<input type="number" class="num-item" />
<button class="buy-btn">Add to Cart</button>
</form>
</div>
<div class="buy-config">
<form class="buy-form" name="buy-form">
<label>Quantity:</label>
<input type="number" class="num-item" />
<button class="buy-btn">Add to Cart</button>
</form>
</div>
You can use the jQuery selector.
<script src="http://code.jquery.com/jquery-1.12.0.min.js"></script>
<script>
$(document).ready(function() {
$('.buy-btn').click(function(){
$(this).parent('form').submit();
});
});
</script>
<form class="buy-form">
<label>Quantity:</label>
<input type="text" class="num-item" />
<button class="buy-btn">Add to Cart</button>
</form>
The code above will setup a function for each HTML elements that has the css class buy-btn.
You can select anything using parent, children, prev, next or find function from jQuery.
Of course this is just a basic exemple I'm showing here, and again some simple example could be :
$('.buy-btn').click(function(){
$(this).parent('form').submit();
//var itemCount = $('#item-count').html();
//itemCount++;
//$('#item-count').html(itemCount);
var numItem = $(this).prev('.num-item').val();
$('#item-count').html(numItem);
});
Unfortunately, you're going to have to loop through the elements in your JavaScript and assign the function to each, however you can do it a bit simpler with some querySelector methods thrown in:
window.onload = function() {
var getCart = document.getElementById('item-count');
var forms = document.querySelectorAll('.buy-form');
var numItems = 0;
var isNum = function(n) {
return(!isNaN(parseFloat(n)) && isFinite(n));
};
var handler = function(e) {
(e || event).preventDefault();
var getInput = this.querySelector('.num-item').value;
if(isNum(getInput)) {
numItems += parseInt(getInput);
getCart.innerHTML = numItems;
this.reset();
} else {
alert("Please enter a valid number");
}
};
for(var i = 0, len = forms.length; i < len; i++) {
forms[i].addEventListener('submit', handler);
}
};
I have an input field that I want to populate with the product of two input fields that appear earlier in the form.
<div class="form-group">
<label for="item_name" class="col-lg-2 control-label">Item:</label>
<div class="col-lg-2">
<input type="text" name="item_name[]" placeholder="Name">
</div>
<div class="col-lg-2">
<input type="text" name="item_qty[]" placeholder="Quantity">
</div>
<div class="col-lg-2">
<input type="text" name="item_price[]" placeholder="Price">
</div>
<div class="col-lg-2">
<input type="text" name="item_total[]" placeholder="Total">
</div>
</div>
These input fields can occur multiple times, so I'm attempting to loop over the item_total[] arrray and attach a listener to the focus event.
$.each($("[name='item_total[]']"), function( index, value ) {
$(this).focus(function() {
var value = ?
//not sure how to select the value of the two previous input fields
// var value = $("item_qty[index]") * $("item_price[index]");
console.log(value);
});
});
You can do like this
$('input[name="item_qty[]"],input[name="item_price[]"]').on("change",function (){
var $container = $(this).closest('.form-group');
qty = Number($('input[name="item_qty[]"]',$container).val())||0,
price = Number($('input[name="item_price[]"]',$container).val())||0;
$('input[name="item_total[]"]',$container).val(qty * price);
})
Another solution starts with selector:
$('input[name^="item_qty"],input[name^="item_price"]').on("change",function (){
var $container = $(this).closest('.form-group');
qty = Number($('input[name^="item_qty"]',$container).val())||0,
price = Number($('input[name^="item_price"]',$container).val())||0;
$('input[name^="item_total"]',$container).val(qty * price);
})
Following assumes that you have [] in input names due to repeating rows and will isolate values within repeated row instances
You can traverse to the nearest wrapping container which would be form-group using closest(), then look within that container using find()
I think what you want is to apply change handler to the user inputs and calculate total when they change
$("input[name=item_qty\\[\\]], input[name=item_price\\[\\]]").change(function(){
var $container = $(this).closest('.form-group');
var qty = $container.find('[name=item_qty\\[\\]]') || 0;
var price = $container.find('[name=item_price\\[\\]]') || 0;
$container.find('[name=item_total\\[\\]]').val( qty * price );
});
jQuery requires escaping special characters in selectors which is why there are so many \\ above.
See escaping rules in selectors API Docs
Something like the following would work.
var quantityEl = $('input[name="item_qty[]"]'),
priceEl = $('input[name="item_price[]"]'),
totalEl = $('input[name="item_total[]"]')
;
var calculateTotal = function() {
var quantity = +quantityEl.val().trim(),
price = +priceEl.val().trim(),
total = quantity * price
;
if (!isNaN(total)) {
totalEl.val(total);
}
};
priceEl.on('change keyup paste', calculateTotal);
quantityEl.on('change keyup paste', calculateTotal);
You can do soemthing like this
input1 = $(this).closest($("[name='item_price']")).val()
Or like this
input1 = $("[name='item_price']")[index]).val()
I wonder if it's possible in jQuery/JS:
If “foobar” is removed or gone from the HTML code
<div id="foo">
<div id="line1">...</div>
<div id="line2">foobar</div>
</div>
I'd like to automatically add “new”
<div id="foo">
<div id="line1">...</div>
<div id="line2">new</div>
</div>
I'd like to have "new" displayed when someone deleted "foobar" from #line2. It's for attribution purposes.
If you make the text the value of an input you can bind to it's change event:
<div id="foo">
<div id="line1">...</div>
<div id="line2"><input type="text" value="foobar" /></div>
</div>
$('#line2').children('input').on('change', function () {
var $this = $(this);
if ($this.val() == '') {
$this.val('new');
}
});
Here is a demo: http://jsfiddle.net/u9Twu/
Note that if you want to programatically change the value of the input you have to manually call .trigger('change') on the input after you change it's value for the change event handler to run.
Also note that .on() is new in jQuery 1.7 and in this case is the same as .bind().
UPDATE
var $foo = $('#foo'),
$line2 = $foo.children('#line2');
if ($line2.length == 0) {
//no #line2 element is found
$foo.append('<div id="line2">new</div>');
} else if ($line2.text().length == '') {
//#line2 element is empty
$line2.text('new');
} else if ($line2.text() != 'foobar') {
//#line2 element does not contain only the string: foobar
$line2.text('new');
}
Here is a demo: http://jsfiddle.net/u9Twu/1/
$('#foo').click(function() {
$('#line2').remove();
$(this).append('<div id="line3">new foobar</div>');
})
http://jsfiddle.net/y5FDs/
I know how to get fields to validate with JavaScript using methods such as getElementById etc. For this instance I need to use the getElementByName method. I have the error 'Cannot read property 'nodeValue' of null in console.log.
Here is code that I used with the getElementByName method which worked
HTML
<button name="button1">Hello</button>
<div class="form-row">
<div class="field w100">
<label for="primary_phone">Primary phone (digits only) *</label>
<input type="text" name="primary_phone" id="primary_phone" placeholder="hello"></input>
</div>
</div>
<div class="form-row">
<label for="confirm_phone">Confirm phone (digits only) *</label>
<input type="text" name="confirm_phone" id="confirm_phone"></input>
</div>
</div>
JavaScript
var btn1 = document.getElementsByName('button1')[0];
var btn1Text = btn1.firstChild.nodeValue;
console.log(btn1Text);
Below is the code that is returning the error.
HTML
<button id="button">Button</button>
JavaScript
function validate() {
var primaryNo = document.getElementsByName('primary_phone')[0];
var confirmNo = document.getElementsByName('confirm_phone')[0];
var primaryValue = primaryNo.firstChild.nodeValue;
var confirmValue = confirmNo.firstChild.nodeValue;
if (primaryValue !== confirmValue) {
alert('Numbers do not match');
} else {
alert('congratulations')
}
};
var btn = document.getElementById('button');
btn.addEventListener('click', validate, false);
Any ideas?
Looks like you might be having input fields whose value you are trying to fetch.
In that case, they don't have any child elements, instead you need to get their value like
var primaryValue = primaryNo.value;
var confirmValue = confirmNo.value;
What is the result of
var btn1 = document.getElementsByName('button1')[0];
in console (console.log(btn1);) ?
Be careful with tag names: button, button1... maybe you have a syntax mistake.