Generating additional rows in PHP form with alternative id and name - javascript

I am looking for a way to add the following row of inputs using a button (and I've found plenty of examples) BUT most of them renames the name of html element (e.g. name = 'price1', name = 'price2') but my javascript references the element's id, making it erroneous when new rows are added. Some helps are appreciated.
JS Fiddle just to see the rows
https://jsfiddle.net/n4h5uwvk/
the HTML code
<form action = "" method = "POST">
<label>Item : </label>
<select id = 'item_name' name = 'item_name' onChange = 'listMatch(this);fieldCheck();'
>
<option value = "" disabled = "disabled" selected="selected">Please Select</option>
<?php
while($row = mysqli_fetch_assoc($result)){
echo "<option value = '".$row['PRODUCT_ID']."' data-price ='
".$row['UNIT_PRICE']."' >".$row['PRODUCT_NAME']."</option>";
}
?>
</select>
<label>Price : </label>
<input type = 'text' id = 'item_price' name = 'item_price' value = '' disabled/>
<label>Quantity : </label>
<input type = "number" id = 'quantity' name = 'quantity' max = "150" min = "0" onChange = 'multiplier(value)' disabled/>
<label>Sub-Total : </label>
<input type = "number" id = 'sub-total' name = 'sub-total' disabled value = ''/>
and the Javascript
<script>
//lists the price according to selected item
function listMatch(product){
var x = product.options[product.selectedIndex].getAttribute('data-price');
document.getElementById('item_price').value = x;
}
//un-disable quantity field after item is selected
function fieldCheck(){
document.getElementById('quantity').removeAttribute('disabled');
}
//var z = quantity*price
function multiplier(value){
var x = document.getElementById('item_price').value;
var y = value;
var z = x*y;
document.getElementById('sub-total').value = z.toFixed(2);
}
//clone fields on 'add field' button click
Updated :
I found a code to clone my forms well, but I encounter another problem. The clone will always duplicate values of the first row, I want to create child rows that have empty values. Any ways around this code?
//global variable for duplication identification
var count = 1;
//clone form for multiple entries
(function() {
$('#add').click(function() {
var source = $('form:first'),
clone = source.clone();
clone.find(':input').attr('id', function(i, val) {
return val + count;
});
clone.insertBefore(this);
count++;
});
})();

As you know id has to be unique and adding numbers to the cloned form elements to keep the ids unique seems overdoing it.
Names don't have to be unique though, so you can have different forms with elements with the same name. And they can be accessed easily by their names:
<form name="form_1">
<input name="firstName" type="text" />
<input name="lasttName" type="text" />
</form>
<form name="form_2">
<input name="firstName" type="text" />
<input name="lasttName" type="text" />
</form>
You can use the form name to access specific element, to access the input with name="firstName" in form_1 and form_2 you can use:
var firstName1 = document.form_1.firstName;
var firstName2 = document.form_2.firstName;
So it will be easy to distinguish between different forms, although their elements have the same structure and names. You just create a new form with name="form_X" and use innerHTML to add the cloned elements.
And to clone an element you can use .cloneNode(true); (or jQuery's clone()).
EDIT:
You still seem to think of it that you need to store everything in a variable, here's an example to do it all, and you can see it's much simpler than you think. I give these forms class="contactForm" to separate them from other forms there might be. we can clone 10 .contactForm and have 100 other forms in the page as well.
To get number of forms you can use $('form.contactForm').length
To empty text inputs inside new form you can use: newForm.find('input[type=text]').val("");
jsfiddle DEMO

Related

Which API I need to use instead of serializeArray to get the custom attributes of fields?

I'm using serializeArray() to retrive the form attributes. When I try to get the attributes, I'm receiving name and value for all the fields.
I have checked the documentation https://api.jquery.com/serializeArray/. I understood it will return the name and value of all the fields.
Now I have few custom attributes for some fields. I want to retrieve them using those custom attributes.
How can i achieve this?
Here is my logic.
var data = $('form').serializeArray();
var newData = {};
var queue = {};
data.forEach(function(field) {
if( field.customField != undefined && field.customField.indexOf("true")>=0 ) {
queue[field.name] = frm.value
} else {
newData[frm.name] = frm.value;
}
});
I need to get that customField attribute, I'm adding that to the HTML field attribute.
May not be the best, but you can do like this.
Let's say you have set of text boxes, text areas and so on with custom data attributes in it. What I am doing here is adding a class to those fields that you need to get value / data attributes in it.
Let's take the following HTML as an example.
HTML
<form id="frm">
<input class="serialize" type="text" name="title1" value="Test title 1" data-test1="test AAA" data-test2="test BBB" /><br/>
<input class="serialize" type="text" name="title2" value="Test title 2" data-test1="test CCC" data-test2="test DDD" /><br/>
<textarea class="serialize" data-test1="textarea test 1">TEST 22 TEST 11</textarea>
<button id="btn" type="button">Serialize</button>
</form>
What I am doing here is iterating through fields which has class .serialize and putting value, name, data attributes and so on to an array.
jQuery
$(document).ready(function(){
$('#btn').on('click', function(e) {
var dtarr = new Array();
$(".serialize").each(function(){
var sub = new Array();
sub['name'] = $(this).attr('name');
sub['value'] = $(this).val();
//data attribute example
sub['data-test1'] = $(this).data('test1');
sub['data-test2'] = $(this).data('test2');
dtarr.push(sub);
});
// This will give you the data array of input fields
console.log(dtarr);
});
});
Hope this helps.

How to access html form values from nested inputs

I'm trying to validate input from this form:
<form id = "mpath" name = "mpath" action = './../cgitest.cgi' method="POST" onsubmit = "return validateForm(this)">
Total Time (in ms): <input type = "text" name = "ttime">
Number of Cars (1-10): <input type = "text" name = "carnum">
Initial Speed (fps): <input type = "text" name = "initspeed"><br>
<!--extraRowTemplate will be repeated for every change in the accleration of the
head car -->
<p class = "extraRowTemplate" name = "extraRowTemplate">
Change:
<select name="change">
<option value="acc">Acceleration</option>
<option value="dec">Deceleration</option>
</select>
Start time: <input type = "text" name="starttime">
End time: <input type = "text" name="endtime">
Amount (in fps): <input type = "text" name="amount"><br>
</p>
<div id = 'container'></div>
<i class="icon-plus-sign"></i>Add Change<br>
<input type="submit" value="Load Head Car">
</form>
Using this function (I haven't written any of the actual validation):
<script type="text/javascript">
function validateForm(form){
var tt = document.forms[0].ttime.value;
var cn = document.forms[0].carnum.value;
var is = document.forms[0].initspeed.value;
var sta = form.elements[4].value;
console.log(tt);
console.log(cn);
console.log(is);
console.log(sta);
if(tt == ""){
alert("starttime must be filled out");
return false;
}
//return false;
}
</script>
But when I try to submit values, it only finds the values for ttime, carnum, and initspeed, and not the value of starttime, endtime, or amount. Also, the value of change is always "acc", even if I set it to "deceleration".
For those wondering why I don't simply remove extraRowTemplate, I need to have those input options in a nested section because I have an option to duplicate them.
I've tried to pass the form as an argument to the function (as shown) as well as just use document.forms[0] to access it. Neither produce the correct result.
Also, when I remove the .value from the form.elements[4].value and set:
var sta = form.elements[4];
The console prints out:
<input type = "text" name = "starttime">
Does anyone know how I can access the value of the nested inputs?
I suppose I should also say that the form works correctly in every other way, and when I send it to the cgitest.cgi, I can access all inputs. I just don't want to validate the inputs on the server side.
EDIT:
If instead of using an onsubmit function (validateForm in my case), I use an event listener:
<script type="text/javascript">
var button = document.querySelector('input[type=submit]')
button.addEventListener('click', function onClick(event) {
var ttime = document.querySelector('input[name=ttime]')
var carnum = document.querySelector('input[name=carnum]')
var initspeed = document.querySelector('input[name=initspeed]')
var change = document.querySelector('select[name=change]')
var starttime = document.querySelector('input[name=starttime]')
var endtime = document.querySelector('input[name=endtime]')
var amount = document.querySelector('input[name=amount]')
console.info('ttime', ttime.value)
console.info('carnum', carnum.value)
console.info('initspeed', initspeed.value)
console.info('change', change.value)
console.info('starttime', starttime.value)
console.info('endtime', endtime.value)
console.info('amount', amount.value)
event.preventDefault()
})
</script>
With the input ttime = 1, carnum = 2, initspeed = 3, change = "acc", starttime = 4, endtime = 5, amount = 6, I get the following console output:
(index):70 ttime 1
(index):71 carnum 2
(index):72 initspeed 3
(index):73 change acc
(index):74 starttime
(index):75 endtime
(index):76 amount
As can be seen, all values beyond initspeed (everything inside extraRowTemplate) are empty. Like I said before, they are not empty when sent to the form action url.
Can you try removing the extraRowTemplate and submit. If it's working, than you can try generating the elements inside with the different ids, because now you have duplicated items with no distinction.
You are currently accessing the elements in a bit of a roundabout way, using document.forms[0]. Also I don't see any code to get the value of the starttime input. You are testing tt in the if, but that was assigned the value of ttime.
document.querySelector
Might I suggest accessing the form elements by name directly, using document.querySelector? This method accepts a CSS selector and returns the first element that matches. Using a simple CSS3 selector we can select elements by name and assuming those names are unique on the page, we will get the right inputs. You could also use form.querySelector if the names are only unique within the form.
Example
var myInput = document.querySelector('input[name=ttime]')
I find document.querySelector and document.querySelectorAll (which gets all elements matching the CSS selector) very useful and use them all the time.
Runnable code snippet
Run this snippet and press the form submit button to print the values of the inputs. Try it and see how it works.
var button = document.querySelector('input[type=submit]')
button.addEventListener('click', function onClick(event) {
var ttime = document.querySelector('input[name=ttime]')
var carnum = document.querySelector('input[name=carnum]')
var initspeed = document.querySelector('input[name=initspeed]')
var change = document.querySelector('select[name=change]')
var starttime = document.querySelector('input[name=starttime]')
var endtime = document.querySelector('input[name=endtime]')
var amount = document.querySelector('input[name=amount]')
console.info('ttime', ttime.value)
console.info('carnum', carnum.value)
console.info('initspeed', initspeed.value)
console.info('change', change.value)
console.info('starttime', starttime.value)
console.info('endtime', endtime.value)
console.info('amount', amount.value)
event.preventDefault()
})
<form id = "mpath" name = "mpath" action = './../cgitest.cgi' method="POST" onsubmit = "return validateForm(this)">
Total Time (in ms): <input type = "text" name = "ttime">
Number of Cars (1-10): <input type = "text" name = "carnum">
Initial Speed (fps): <input type = "text" name = "initspeed"><br>
<!--extraRowTemplate will be repeated for every change in the accleration of the
head car -->
<p class = "extraRowTemplate" name = "extraRowTemplate">
Change:
<select name="change">
<option value="acc">Acceleration</option>
<option value="dec">Deceleration</option>
</select>
Start time: <input type = "text" name="starttime">
End time: <input type = "text" name="endtime">
Amount (in fps): <input type = "text" name="amount"><br>
</p>
<div id = 'container'></div>
<i class="icon-plus-sign"></i>Add Change<br>
<input type="submit" value="Load Head Car">
</form>
I can access the value of your "starttime" field in Firefox/Chrome/Opera using either
var sta = document.forms[0][4].value
or
var sta = document.forms[0].starttime.value
I was able to figure out what was going wrong. In my css I set:
.extraRowTemplate {
display: none;
}
which was preventing the input values from being sent. Once I removed this my problems went away. Setting "visibility : hidden" is a good alternative that allowed the values to be submitted and the template not visible.

Change value of <input> to include a superscript, using Javascript

The following code works correctly for me, in HTML.
<input type = "text" name = "var_1" id = "i_var_1" value = "x&sup8">
The following, using Javascript, also works:
<p id = "p1"><input type = "text" name = "var_1" id = "i_var_1" value = "0"></p>
<script....>
q1 = document.getElementById("p1");
q1.innerHTML = '<INPUT TYPE = "text" name = "var_1a" id = "i_var_1a" value = "x&sup8">';
</script>
However I need to add in the superscript when a button is pressed. So I have something like:
<p id = "p1"><input type = "text" name = "var_1" id = "i_var_1" value = "0"></p>
<input type = "button" id = "i_button" value = "Add the superscript" onclick="Add_Superscript()";>
<script.....>
function Add_Superscript()
{
q1 = document.getElementById("p1");
b1 = document.getElementById("i_var_1");
c1 = b1.value.toString() + "&sup8";
q1.innerHTML = '<INPUT TYPE = "text" name = "var_1a" id = "i_var_1a" value = c1.value>';
}
</script>
The above code does not reproduce the superscript properly.
Anyone any ideas? Thanks in advance for comments.
Not sure this is what you want, but it adds &sup8 to whatever is in the input box.
function Add_Superscript() {
q1 = document.getElementById("p1");
b1 = document.getElementById("i_var_1");
c1 = b1.value.toString() + "&sup8";
q1.innerHTML = '<INPUT TYPE = "text" name = "var_1a" id = "i_var_1a" value = "' + c1 + '">';
}
<p id="p1">
<input type="text" name="var_1" id="i_var_1" value="0">
</p>
<input type="button" id="i_button" value="Add the superscript" onclick="Add_Superscript()" ;>
I don't know what you're trying to do but maybe it's because of the c1.value ! Try:
q1.innerHTML = '<INPUT TYPE = "text" name = "var_1a" id = "i_var_1a" value =' + c1 + '>';
You have several typos in your code and a lot of unnecessary code as well. You just need to set up a click event handler on the button that populates the value of the pre-existing input. No need to create a new input.
A few notes:
When you were trying to create the new input element (which it turns out you don't need to do in the first place), you had the entire thing as a string. You need to inject the dynamic value into that string, by terminating the string, concatenating the new value in and then concatenating the closing of the string, like this:
q1.innerHTML = '<input type="text" name="var_1a" id="i_var_1a" value=' + c1.value + '>';
Next, it's best to use good naming conventions for elements and variables. Prefix an id and name with something that describes the "type" of thing the element is. Use btn (button), txt (textbox), chk (checkbox), rad (radio button), etc. And don't use _ (that's a very old convention). Instead use "camelCase". Further, with form elements, you need to give them a name for form submission purposes, but it is also a good idea to give them and id for CSS and JavaScript purposes. Use the same id that you used for name so that you don't have two different names for the same thing.
Lastly, don't configure your HTML elements to event handlers via HTML attributes (onclick, onmouseover, etc.). Doing this creates global anonymous functions that alter the this binding in the callback function, it creates "spaghetti code" that is hard to scale and debug and it doesn't follow the W3C DOM Event specification. Instead, do all the work in JavaScript and use .addEventListener() to connect functions to events.
// Get references to the relevant DOM elements
var btn = document.getElementById("btnGo");
var input = document.getElementById("txtInput");
// Set up a click event handling function
btn.addEventListener("click", add_Superscript);
function add_Superscript(){
// Create a new value that is the old value plus a "superscript" value
var newVal = input.value + "&sup8";
// Update the input with the new value:
input.value = newVal;
}
<p>
<input type="text" name="txtInput" id="txtInput" value="0">
</p>
<input type = "button" id="btnGo" value="Add the superscript">

How would I use jQuery to manipulate a html form when there are nested elements involved?

I have an empty form that needs to be filled with what I'd like to call mini-forms dynamically based on a condition. For example,this can be a form that asks for the names and locations of restaurants. Now, based on the number of restaurants(let's say 'm'), I'd like to add to the big form 'm' mini-forms that asks for the name and location. How can I use jQuery to create each of these mini-forms, that take in the name and the location of the restaurant and append them each to the big form. The html would look something like this. But I need to create this dynamically based on how many forms the user would need, and if he would need any.
Edit - I have learned that we cannot nest forms. I have renamed the inner 'form' elements to 'div'.
<form>
<div id = 1>
Name: <input type = "text" name = "name">
Location: <input type = "text" name ="location>
</div>
<div id = 2>
Name: <input type = "text" name = "name">
Location: <input type = "text" name ="location>
</div>
...
</form>
First you need to look for changes to the input where the user enters the number of restaurants:
$('#noofrestaurants').change(function(){
Then you need to loop through the number inputted and create new inputs each time:
var restaurants = $('#noofrestaurants').val();
for (var i = 0; i < restaurants; i++){
$('#miniformcontainer').append('<input type="text" name="rest_name[]"/><input type="text" name="rest_loc[]"/>');
}
});
You could try something like this:
<script>
function addMiniForms(n)
{
for (i=0; i<n ; i++)
{
var $div = $("<div id='" + i + "'></div>");
var $labelName = $("<label for='name" + i + "'>Name</label>");
var $inputName = $("<input type='text' id='name" + i +' />");
var $labelLocation = $("<label for='location" + i + "'>Location</label>");
var $inputLocation = $("<input type='text' id='location" + i +' />");
$div.append($labelName);
$div.append($inputName);
$div.append($labelLocation);
$div.append($inputLocation);
$("#containerid").append($div);
};
};
</script>
I have not tested this code, so it might need some tweaking.
You can't nest forms. If you want to have repeated inputs in a form, give them array-style names:
<div id = 1>
Name: <input type = "text" name = "name[]">
Location: <input type = "text" name ="location[]">
</div>
The back-end should convert these into arrays. For instance, PHP will fill in $_POST['name'] with an array of all the Name inputs.
The jQuery looks like:
divnum++;
$("form").append("<div id='"+divnum+"'>Name: <input type='text' name='name[]'">Location: <input type='text' name='location[]'></div>");

How do I use two .siblings with the same input type?

I want to get "The walking dead" also but it only gets the first hidden. Can i put a class on .this or how should I do?
$(".articel input[type='button']").click(function(){
var price = $(this).siblings("input[type='hidden']").attr("value");
var quantity = $(this).siblings("input[type='number']").attr("value");
var name = $(this).siblings("input[type='hidden']").attr("value");
var ul = document.getElementById("buylist");
var prod = name + " x " + quantity + " " + price + "$";
var el = document.createElement("li");
el.innerHTML = prod;
ul.appendChild(el);
<form class="articel">
Quantity: <input type="number" style="width:25px;"><br>
Add to cart: <input type="button" class="btn">
<input type="hidden" value="30">
<input type="hidden" value="The walking dead">
</form>
The conventional way to identify form fields is by the name property.
HTML:
<input type="hidden" name="title" value="The walking dead">
jQuery:
var name = $(this).siblings('input[name=title]').val();
Your current selector, siblings("input[type='hidden']"), selects all hidden field siblings, but since you have no way to discern them, attr will always just yield the value of the first match.
You could also have iterated over your collection of elements, or accessed them by index siblings('input[type=hidden]:eq(1)') or siblings('input[type=hidden]').eq(1), for instance, but it is a poor design that will break your code if you add another hidden field for something else. You really should prefer to name your elements so that you can access them in a meaningful way and know your data. That way you'll be free to move around and modify your markup according to new requirements, without breaking your script.
By the way, I'm using .val() above, which is shorthand for .attr('value').
One option is to use special selectors, e.g. :first and :last:
var price = $(this).siblings("input[type='hidden']:first").attr("value");
var name = $(this).siblings("input[type='hidden']:last").attr("value");
However, you always can set a class name to the elements:
<input type="hidden" class="price" value="30">
<input type="hidden" class="name" value="The walking dead">
var price = $(this).siblings(".price").attr("value");
var name = $(this).siblings(".name").attr("value");
I would add an class name to your hidden inputs (price, name). This way the html source code is more readable and also the js code will be more readable.

Categories