I have a form to add users to a select list from 2 textboxes (Last name and First name).
When I click on the "+" button, it adds an option with the last name and first name specified to the select element below. Right now, it adds the option with only one white space between last and first name, but I would like the first name to be aligned with the above "First name" textbox.
Here's a fiddle with my sample code: http://jsfiddle.net/fx37j71s/12/
<table>
<tr>
<td>Last Name</td>
<td>First Name</td>
</tr>
<tr>
<td><input type="text" id="txtlastname" /></td>
<td><input type="text" id="txtfirstname" /></td>
<td><input type="button" value="+" onclick="addemployee();" /></td>
</tr>
<tr>
<td colspan="2"><select id="lbxname" size="5" style="width:500px"></select></td>
<td valign="top"><input type="button" value="-"onclick="removeemployee();" /></td>
</tr>
</table>
And the addemployee() function:
function addemployee()
{
var lastname = document.getElementById('txtlastname');
var firstname = document.getElementById('txtfirstname');
var select = document.getElementById('lbxname');
var option = document.createElement('option');
var text = document.createTextNode(lastname.value + ' ' + firstname.value);
option.appendChild(text);
select.appendChild(option);
}
Is there a way to achieve this in JS or jquery or maybe CSS? I have tried to add a fixed amount of spaces minus the amount of characters in Last name, but the actual width of the string depends on the characters (i.e. "PPPPP" is wider than "lllll" even though they both have 5 characters). I also found the "clientWidth" property, but I can't seem to make it work properly.
Thank you :)
Instead of creating textNode can set innerHTML
Something like:
function addemployee()
{
var lastname = document.getElementById('txtlastname');
var firstname = document.getElementById('txtfirstname');
var select = document.getElementById('lbxname');
var option = document.createElement('option');
option.innerHTML = padStr(lastname.value) + firstname.value;
select.appendChild(option);
}
function padStr(str){
while(str.length < 500){
str += ' ';
}
return str
}
DEMO
Based on charlietfl's answer and Evilzebra's comment, this worked for me:
Updated fiddle: http://jsfiddle.net/vcfpd450/2/
function addemployee()
{
var lastname = document.getElementById('txtlastname');
var firstname = document.getElementById('txtfirstname');
var select = document.getElementById('lbxname');
var option = document.createElement('option');
option.innerHTML=padStr(lastname.value) + firstname.value;
select.appendChild(option);
}
function padStr(str){
var x = str.length;
while(x < 31){
str+=' ';
++x;
}
return str;
}
CSS:
#lbxname
{
font-family: monospace;
}
Basically, I add spaces to the string until I reach the desired width (31 in this case). Using a monospace font-family makes sure the width is consistent with the number of characters.
Related
Sorry the title is vague, but I have a form that accepts multiple id and posts the users input to URL to open x amount of tabs depending on the number of account id's.
The link for the first account id is opening with the values inserted into the form but the second account id is just showing "undefined" and from console looks like the second account id isn't getting past the first declaration but skipping to the second.
<form accept-charset="UTF-8" method="post"><div style="margin:0;padding:0;display:inline">
<table class="vat-tax-processor center-table">
<tbody>
<tr>
<td>
<span class="required">*</span>
AWS Account ID (No Dashes)<br>
</td>
<td><textarea autocomplete="off" id="AccountIDs" name="AccountIDs" value=""></textarea></td>
<tr>
<td>
<span class="required">*</span>
VAT Country <br>
</td>
<td><input autocomplete="off" type="text" value="" id="vatCountryCode" name="vatCountryCode"></td>
</tr>
<tr>
<td>
<span class="required">*</span>
Vat Number<br>
</td>
<td><input autocomplete="off" type="text" value="" id="vatNumber" name="vatNumber"></td>
</tr>
<tr>
<td>
<span class="required">*</span>
Registration Type <br>
</td>
<td><input autocomplete="off" type="text" value="Intra-EU" id="currentState" name="currentState"></td>
</tr>
<tr>
<td>
<span class="required">*</span>
Business Legal Name <br>
</td>
<td><input autocomplete="off" type="text" value="" id="businessLegalName" name="businessLegalName"></td>
</tr>
<tr>
<td>
Here is my js:
function addExemption(){
var AccountIDsArray = $('textarea[id=AccountIDs]').val().split('\n');
var vatCountryCodeArray = $('input[id=vatCountryCode]').val().split('\n');
var vatNumberArray = $('input[id=vatNumber]').val().split('\n');
/*var currentStateArray = $('input[id=currentState]').val().split('\n');*/
var businessLegalNameArray = $('input[id=businessLegalName]').val().split('\n');
console.log('I got past part 1 declarations - No issues here');
$.each(AccountIDsArray, function(index, value){
var AccountID = AccountIDsArray[index];
var vatCountryCode = vatCountryCodeArray[index];
var vatNumber = vatNumberArray[index];
/*var currentState = currentStateArray[index];*/
var businessLegalName = businessLegalNameArray[index];
console.log('I got part part 2 declarations - No issues here either');
console.log(AccountID);
var URL = 'https://linkhere';
var URL_Final = encodeURI(URL);
window.open(URL_Final, '_blank');
}
);
Here is a screenshot of what appears on first link and second link:
Account 1
Account 2
There are a couple issues I see with this.
The window is opening in your loop meaning that it will open a window immediately after the first id is printed to the console. I would move window.open() outside of the $.each.
You are risking out of bounds indexing on vatCountryCodeArray, vatNumberArray, currentStateArray and businessLegalNameArray since they are input elements and not textareas.
The 'Undefined' you see if because your function has no return value. See here.
function addExemption(){
var AccountIDsArray = $('textarea[id=AccountIDs]').val().split('\n');
var vatCountryCodeArray = $('textarea[id=vatCountryCode]').val().split('\n');
var vatNumberArray = $('textarea[id=vatNumber]').val().split('\n');
var currentStateArray = $('textarea[id=currentState]').val().split('\n');
var businessLegalNameArray = $('textarea[id=businessLegalName]').val().split('\n');
console.log('I got past part 1 declarations - No issues here');
$.each(AccountIDsArray, function(index, value){
if(value != null && value != ''){
var AccountID = value;
//var vatCountryCode = vatCountryCodeArray[index];
//var vatNumber = vatNumberArray[index];
//var currentState = currentStateArray[index];
//var businessLegalName = businessLegalNameArray[index];
console.log('I got part part 2 declarations - No issues here either');
console.log(AccountID);
}
});
var URL = 'https://linkhere';
var URL_Final = encodeURI(URL);
window.open(URL_Final,'_blank');
return '';
}
I was able to resolve this like so:
function addExemption(){
var AccountIDsArray = $('textarea[id=AccountIDs]').val().split('\n');
console.log('I got past 1st declarations - No issues here');
$.each(AccountIDsArray, function(index, value){
var AccountID = AccountIDsArray[index];
var vatCountryCode = $('#vatCountryCode').val();
var vatNumber = $('#vatNumber').val();
var businessLegalName = $('#businessLegalName').val();
console.log('I got past 2nd declarations - No issues here either');
console.log(AccountID);
var URL = 'https:xxxxx?accountId=' + AccountID + '&vatCountryCode=' + vatCountryCode + '&vatNumber=' + vatNumber + '¤tState=Intra-EU&businessLegalName=' + businessLegalName + '';
var URL_Final = encodeURI(URL);
window.open(URL_Final, '_blank');
});
}
I have a table that makes automatically 2 calculations:
Calculation of numbers of days after the selection of arrived and departed date from two input date field with calendar, result is stored is field (nbjours)
Multiplication of 3 fields (nbcheveaux * days* price), result is stored ind field (total)
There is a button that when we click on it a new row is added. How can i reproduce the same automatic calculations on the news rows added after click ?
1- my add rows function
window. addRow = function addRow(btn) {
var parentRow = btn.parentNode.parentNode;
var table = parentRow.parentNode;
var tr = document.createElement("tr");
var tdNbC = document.createElement("td");
var tdDateArrive = document.createElement("td");
var tdDateDepart = document.createElement("td");
var tdNbJour = document.createElement("td");
var tdPrix = document.createElement("td");
var tdTotal = document.createElement("td");
var td3 = document.createElement("td");
var inputDateArrive = document.createElement("input");
var inputDateDepart = document.createElement("input");
inputDateArrive.type = "text";
inputDateDepart.type = "text";
inputDateArrive.setAttribute("class", "date");
inputDateDepart.setAttribute("class", "date1");
var inputNbrC = document.createElement("input");
var inputNbrJour = document.createElement("input");
var inputPrix = document.createElement("input");
var inputTotal = document.createElement("input");
var inputButton = document.createElement("button");
inputButton.type = "button";
inputButton.innerHTML = "+";
inputButton.onclick = function(){
addRow(this);
};
tdNbC.appendChild(inputNbrC);
tdDateArrive.appendChild(inputDateArrive);
tdDateDepart.appendChild(inputDateDepart);
tdNbJour.appendChild(inputNbrJour);
tdPrix.appendChild(inputPrix);
tdTotal.appendChild(inputTotal);
td3.appendChild(inputButton);
tr.appendChild(tdNbC);
tr.appendChild(tdDateArrive);
tr.appendChild(tdDateDepart);
tr.appendChild(tdNbJour);
tr.appendChild(tdPrix);
tr.appendChild(tdTotal);
tr.appendChild(td3);
table.appendChild(tr);
$(inputDateDepart).mask("99/99/9999");
$(inputDateArrive).mask("99/99/9999");
}
2- function that calculate numbers of days
$(document).ready(function() {
$('.date1').change(function() {
var start = $('.date').datepicker('getDate');
var end = $('.date1').datepicker('getDate');
if (start<end) {
var days = (end - start)/1000/60/60/24;
$('.days').val(days);
}
else {
alert ("Depated date must be greater that arrived date!");
$('.date').val("");
$('.date1').val("");
$('.days').val("");
}
}); //end change function
}); //end ready
3- Function that operate the multiplication
$('.nbrcevaux,.days,.price').keyup(function() {
var nbrcevaux = parseInt($('.nbrcevaux').val());
var days = parseInt($('.days').val());
var prix = parseInt($('.price').val());
$('.total').val(nbrcevaux * days * prix );
});
4- HTML Table
<table>
<tr>
<td class="centrer">Nbr de chevaux</td>
<td class="centrer">Arrived Date</td>
<td class="center">Departed Date</td>
<td class="centrer">Nb/Days</td>
<td class="centrer">Prix/jr/ cheval/boxe</td>
<td class="centrer"> Total</td>
</tr>
<tr>
<td><input type="text" name="nbrcevaux" class="nbrcevaux" /></td>
<td><input type="text" name="datearrive" class ="date"/> </td>
<td><input type="text" name="datedepart" class ="date1" /></td>
<td><input type="text" name="nbrjours" class ="days" /></td>
<td><input type="text" name="prix" class="price" /></td>
<td><input type="text" name="total" class="total" /></td>
<td><button type="button" onClick ="addRow(this)">+</button> </td>
</tr>
How can i integrate the functions calculate numbers of days and multiplication in the added new row displyed after click ?
So, I was bored and tackled your question, by rewriting it because you had quite a bit of superfluous code.
Your main issue (with the calculations on the added rows) stems from the fact that you were relying on classes to uniquely identify elements, but that won't cut it. Each new row and element within the row needs to have its own unique id.
I also took the liberty of making sure that there will only ever be one "Add row" button, as you'll see.
This working example has comments inline to help follow what's going on.
$(function() {
// Declare & initialize module wide variables to store DOM elements:
var $txtnbrcevaux = $("#nbrcevaux"), $txtDateArrive = $("#dateArrive"),
$txtDepart = $("#datedepart"), $txtnbrjours = $("#nbrjours"), $txtPrix = $("#prix"),
$txtTotal = $("#total"), $btnAdd = $("#btnAddRow"), $masterRow = $("#master1");
// Unique value that will identify new elements
var count = 1;
// Establish the date picker fields
$txtDateArrive.datepicker();
$txtDepart.datepicker();
// Wire up the button's click event:
$btnAdd.on("click", function(){
// Make a copy of the last row
var newTR = $("tr[id=master" + count + "]").clone(true);
// Update the new row's id to be unique
newTR[0].id = "master" + (count + 1);
// Loop through the child elements and modify their id's so that they are unique
newTR.children().each(function(index){
if(this.children.length > 0){
// Wipe out old (copied values)
this.firstChild.value = "";
var oldID = this.firstChild.id;
this.firstChild.id = oldID.substring(0, oldID.length) + (count + 1);
// Cloning datepickers creates problems because the clones remain bound to the
// original input element. Here, we'll create a new input element and then
// insert it where the current one is, then we'll remove the current one:
if($(this.firstChild).is(".date, .date1")){
var newPicker = document.createElement("input");
newPicker.id = this.firstChild.id;
newPicker.name = this.firstChild.name;
newPicker.setAttribute("class", this.firstChild.className.replace(" hasDatepicker", ""));
newPicker.style.width = "80px";
// Set up the new datepicker:
$(newPicker).insertAfter(this.firstChild);
$(this.firstChild).remove();
$(newPicker).datepicker();
}
}
});
// Increment the count so the next row will use the next number for its id's
count++;
// Hide the last row's button
this.style.display = "none";
// Add the new row to the table
$("table").append(newTR);
// Commented due to not having plugin available
// $(inputDateDepart).mask("99/99/9999");
// $(inputDateArrive).mask("99/99/9999");
});
$('.nbrcevaux, .days, .price').on("keyup", function() {
var nbrCevaux = this.parentElement.parentElement.querySelector(".nbrcevaux").value;
var days = this.parentElement.parentElement.querySelector(".days").value;
var prix = this.parentElement.parentElement.querySelector(".price").value;
// Your problem was that you were trying to work with values from
// classes and not specific elements. Changing the function to expect
// the data to be passed to it and having it return the answer allow
// you to control what goes in and where to put what comes out
this.parentElement.parentElement.querySelector(".total").value = nbrCevaux * days * prix;
});
$txtDepart.change(function() {
var start = $txtDateArrive.datepicker('getDate');
var end = $txtDepart.datepicker('getDate');
if (start < end) {
var days = (end - start)/1000/60/60/24;
$txtnbrjours.val(days);
} else {
alert ("Depated date must be greater that arrived date!");
$txtDateArrive.val("");
$txtDepart.val("");
$txtnbrjours.val("");
}
}); //end change function
}); //end ready
/* This is only added to shrink things down so they appear within the space allotted */
input[type=text] {width:80px;}
body {font-size:.5em;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.11.3/jquery-ui.min.js"></script>
<table>
<tr>
<td class="centrer">Nbr de chevaux</td>
<td class="centrer">Arrived Date</td>
<td class="center">Departed Date</td>
<td class="centrer">Nb/Days</td>
<td class="centrer">Prix/jr/ cheval/boxe</td>
<td class="centrer"> Total</td>
</tr>
<tr id="master1">
<td><input type="text" id="nbrcevaux" name="nbrcevaux" class="nbrcevaux"></td>
<td><input type="text" id="dateArrive" name="dateArrive" class ="date"></td>
<td><input type="text" id="datedepart" name="dateDepart" class ="date1"></td>
<td><input type="text" id="nbrjours" name="nbrjours" class ="days"></td>
<td><input type="text" id="prix" name="prix" class="price"></td>
<td><input type="text" id="total" name="total" class="total"></td>
<td><button type="button" id="btnAddRow">+</button> </td>
</tr>
</table>
I've got a table-like structure with text inputs in which I am trying to make an entire row to be removed with all their children, but first passing the values of cells up one by one
in the rows below to keep IDs numbering structure.
The table structure is like this:
<table cellpadding=0>
<tr id="myRow1">
<td id="#R1C1">
<input class="myCell">
</td>
<td id="#R1C2">
<input class="myCell">
</td>
<td id="#R1C3">
<input class="myCell">
</td>
<td id="#R1C4">
<input class="myCell">
</td>
</tr>
<tr id="myRow2">
<td id="#R2C1">
<input class="myCell">
</td>
<td id="#R2C2">
<input class="myCell">
</td>
<td id="#R2C3">
<input class="myCell">
</td>
<td id="#R2C4">
<input class="myCell">
</td>
</tr>
<!-- ...and so on. -->
</table>
Having this table, when some event is triggered,I make this code run:
var rows = 1; // This value is updated when adding/removing a line
//This code runs from any <tr> by event keyup
if (event.altKey) { // I define here all Alt+someKey actions.
// Getting position values
var currentId = $(this).attr('id');
var row = Number(currentId.split('C')[0].substring(1));
var column = Number(currentId.split('C')[1]);
var belowVal;
if (event.which == 66) { //Case Ctrl+B
// If not the last row, start looping
if (rows > row) {
var diff = rows - row;
// Iteration over rows below
for (var i = 0; i < diff; i++) {
// Iteration over each column
for (var c = 1; c <= 4; c++) {
// here I try to get the value from column below
belowVal = $('#R'+(row+1+i).toString() +
'C'+c.toString()).val();
$('#R'+(row+i).toString()+'C' +
c.toString()).find('.myCell').val(belowVal);
}
}
}
$('#myRow'+rows.toString()).empty();
$('#myRow'+rows.toString()).remove();
rows--;
}
}
It works fine for removing the last row, but, when trying to remove an upper row, the values of current row and the ones below become blank instead of moving up. I made this code for each row below to pass it's values to the upper row, but it isn't doing what I wanted.
Why is this happening? I couldn't figure it out.
The problem seem to be, that the ids you are using to access the values are not the ids of the input elements, but rather the ids of the containing table cells.
Here an approach, which doesnt use the ids, but relies on the nodes structure instead, code not tested:
if (event.which == 66) {
var currentrow = $(this);
var currentinputs = currentrow.find('input.myCell');
while(var nextrow = currentrow.next('tr')) {
var nextinputs = nextrow.find('input.myCell');
currentinputs.each(function(index,element){
element.val(nextinputs.get(index).val());
});
currentrow = nextrow;
currentinputs = nextinputs;
}
currentrow.remove();
}
RESOLVED
Thanks to #JHoffmann, I was able to resolve my problem like this:
for (var c = 1; c <= 4; c++) {
// here I try to get the value from column below
belowVal = $('#R'+(row+1+i).toString()+'C'+c.toString())
.find('.myCell').val();
$('#R'+(row+i).toString()+'C'+c.toString())
.find('.myCell').val(belowVal);
}
In the line that assigns a value to belowVal, I forgot to call the method .find('.myCell') before calling .val(). That was the mistake that caused my code to fail, as #JHoffmann commented in his answer.
I've dynamically created rows in a table using javascript that I've altered to suit my needs, within this dynamically created table i want to multiply Qty with price and put that in the total box,
html
<table>
<tbody id="plateVolumes">
<tr>
<td><input type="checkbox" value="None" id="chk" name="chk[]" /></div></td>
<td><input type='text' name='qty' id='qty' class="qty" placeholder='Qty' /></td>
<td><select name="productdescription[]" class="productdescription" id="productdescription">
<option value="Product">Product</option>
<option value="Product01" label="Product01">Product01</option>
<option value="Product02" label="Product02">Product02</option>
<option value="Product03" label="Product03">Product03</option>
<option value="Product04" label="Product04">Product04</option>
<option value="Product05" label="Product05">Product05</option>
<option value="Product06" label="Product06">Product06</option>
</select></td>
<td><input type='text' name='price[]' id='price' class="price" placeholder='Price (£)' onChange="WO()" /></td>
<td><input type='text' name='totalprice[]' id='totalprice' class="price" placeholder='Total Price (£)' /></td>
</tr>
</tbody>
</table>
I am using this javascript code in order to add the values together but this will only work with the first line that isn't created by the code:
javascript
<script>
function WO() {
var qty = document.getElementById('qty').value;
var price = document.getElementById('price').value;
answer = (Number(qty) * Number(price)).toFixed(2);
document.getElementById('totalprice').value = answer;
}
</script>
I'm pretty new with javascript so I'm wondering if there is a way to apply this to the dynamic rows also but keep them separate for when I pass them over to my php mailer.
EDIT: I've been playing with the code and I'm a bit closer to getting the answer I need but I still don't know how to make this give me the answers that I want,
function WO() {
for (var i = 0; i < rowCount; i++) {
var qty = document.getElementsByClassName('qty').value;
var price = document.getElementsByClassName('price').value;
var answer = (Number(qty) * Number(price)).toFixed(2);
document.getElementsByClassName('totalprice[' + i + ']').innerHTML = answer;
}
}
this helped, I've asked a friend who's created this, just thought I'd add it in case anyone else wondered
function WO() {
var tbody = document.getElementById("plateVolumes");
for(var i = 0; i < tbody.rows.length; i++) {
var row = tbody.rows[i];
var qty = row.cells[1].childNodes[0].value;
var price = row.cells[3].childNodes[0].value;
var answer = (Number(qty) * Number(price)).toFixed(2);
row.cells[4].childNodes[0].value = answer;
}
}
In an HTML id should be unique. When you get element by id it always returns the first element it gets.
I would suggest to use class in stead. Run loop for rows and calculate total.
this will be a closer solution... I have not tested though.
var trNodes = document.getElementById('plateVolumes').childNodes;
for(var i=0; i < trNodes.length; i++) {
var qty = trNodes[i].getElementsByClassName('qty').value;
var price = trNodes[i].getElementsByClassName('price').value;
var answer = (Number(qty) * Number(price)).toFixed(2);
trNodes[i].getElementsByClassName('totalprice').innerHTML = answer;
}
reference
I have multiple textfields with same name.
When someone types a number in one of textfield. It should show sum on runtime in Sum Textfield.
Can anyone help me with that?
I have this HTML:
<table width="400" border="1" cellspacing="0">
<tr>
<td colspan="2" align="center">
SUM:
<input type="text" name="sum" id="sum" /></td>
</tr>
<tr>
<td><input type="text" name="textfield" id="field_1" /></td>
<td><input type="text" name="textfield" id="field_2" /></td>
</tr>
<tr>
<td><input type="text" name="textfield" id="field_3" /></td>
<td><input type="text" name="textfield" id="field_4" /></td>
</tr>
</table>
Here is my Fiddle:
http://jsfiddle.net/36Yhe/1/
Using vanilla JavaScript you can do it like this:
(function () {
var textFields = document.getElementsByName('textfield');
sum = function() {
var sum = 0;
for (var i = 0; i < textFields.length; i++) {
var val = textFields[i].value;
if (parseFloat(val) == val) {
sum += parseFloat(val);
}
}
document.getElementById('sum').value = sum;
};
document.getElementById('sum-table').addEventListener("keyup", sum, false);
sum();
})();
JSFiddle
Also your element IDs should be unique where as the name can be the same. I have shown this in the above fiddle.
Edited, with updated fiddle, to include changes suggested by #bfontaine
Try this :
// selects all inputs but "#sum"
var inputs = $('input:not(#sum)');
// each time the user releases a key
inputs.keyup(function () {
var sum = 0;
// loops through every inputs
inputs.each(function () {
// parses input's value into a float
// if parsing fails uses 0 instead of NaN (NaN || 0)
sum += parseFloat($(this).val()) || 0;
});
// displays the result
$('#sum').val(sum);
});
Here is a demo : http://jsfiddle.net/wared/8K24v/.
Another (twisted) solution :
var inputs = $('input:not(#sum)');
inputs.keyup(function () {
$('#sum').val(new Function('return ' + inputs.map(function () {
return parseFloat($(this).val()) || 0;
}).get().join('+') + ';')());
});
And its (twisted) demo : http://jsfiddle.net/wared/sraV3/.
Let's unroll the twisted part :
inputs.map(...).get() : Turns a jQuery list of inputs into an array of numbers.
.join('+') : Turns the array of numbers into a string. Example : [1,2].join('+') gives "1+2".
new Function('return ...;')() : Creates a new function and executes it immediately. At this point we have something like : new Function('return 1+1+1+1;')() (evaluate this code into your browser console, the output is obviously the number 4).
Finally, the result of this function is passed to $('#sum').val(...).
Additional contents :
http://api.jquery.com/map/
http://api.jquery.com/get/
MDN : Array join method
MDN : Function (constructor)
MDN : parseFloat