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>
Related
I have a table, which has an input at the end of each line.
Here is the input:
<td><input data-price='<?= floatval($row['Prix']); ?>' ?>' type="number" name="quantity" id="quantity"></td>
I have a script that takes the price of the data-price in the input and multiplies
it with the number in the input. Right now my script starts off by adding all of the prices, but then it multiplies the total by only the first input in my table.
How can I change my code so that it multiplies each price by the quantity in the input?
Here is the script:
document.getElementById("submit").onclick = function giveTotal() {
var total = 0;
var grandTotal = document.getElementById('grandTotal');
var quantity = document.getElementById('quantity');
var nodes = document.getElementsByName('quantity');
[].forEach.call(nodes, function(node) {
console.log(quantity.value);
console.log(node.dataset.price);
total += (parseFloat(node.dataset.price) * quantity.value)
})
grandTotal.innerHTML = total;
console.log('Total: ' + total);
};
IDs are unique -- no two elements can have the same ID. When you use document.getElementById(), it will return only the first element that matches that ID and no other.
You already have access to each input from your nodes variable, and you're already iterating over them in your forEach loop. So instead of multiplying by quantity.value, you should just be multiplying by node.value so that you're using the value of each specific input.
You need to select each table row by itself like this:
(In this example I assume your table has the id orders)
document.getElementById("submit").onclick = function giveTotal() {
// Get the table element (id="orders")
const $table = document.getElementById('orders');
// Get the grand total element
const $grandTotal = document.getElementById('grandTotal');
// Temporary variable
let total = 0;
// For each input element in the table add the price*value to total
table.querySelectorAll('input').forEach($input => {
total += (parseFloat($input.dataset.price) * $input.value)
});
// Write total to $grandTotal element
$grandTotal.innerText = total;
// Debug output
console.log('Total: ' + total);
};
You can get table rows and process them. Something like this.
document.getElementById('submit').onclick = function() {
var total = Array.from(document.querySelector('#cart tbody')
.querySelectorAll('tr')) //get array
.reduce((acc, cur) => acc + cur.querySelector('td:first-child').innerText * cur.querySelector('input').value, 0);
console.log(total);
};
<table id="cart">
<thead>
<tr>
<th>Price</th>
<th>Qty</th>
</tr>
</thead>
<tbody>
<tr>
<td>5.45</td>
<td><input name="qty" type="text" value="0" />
<!--number is ok too -->
</td>
</tr>
<tr>
<td>7.80</td>
<td><input name="qty" type="text" value="0" />
<!--number is ok too -->
</td>
</tr>
<tr>
<td>0.95</td>
<td><input name="qty" type="text" value="0" />
<!--number is ok too -->
</td>
</tr>
</tbody>
</table>
<button type="button" id="submit">Submit</button>
I am need of help. I am trying to figure out the below:
<script>
var ct = 1;
function new_bank()
{
ct++;
var div1 = document.createElement('div');
div1.id = ct;
// bank to delete extended form elements
var delLink = 'delete';
div1.innerHTML =
document.getElementById("newbanktpl").innerHTML + delLink;
document.getElementById('newbank').appendChild(div1);
}
// function to delete the newly added set of elements
function delIt(eleId)
{
d = document;
var ele = d.getElementById(eleId);
var parentEle = d.getElementById('newbank');
parentEle.removeChild(ele);
findTotalA();
}
</script>
<!-- Template -->
<div id="newbanktpl">
<table>
<tr>
<td></td>
<td><textarea name="BankAccount[]"></textarea></td>
<td><input type="number" onblur="findTotalA()" name="Value[]"/></td>
<td><input type="number" name="Ownership[]" /></td>
<td>**ADD DELETED LINK HERE** </td>
</tr>
</table>
what I am after is the delete function to be within the table - at the moment the delete function is after the newbanktpl, and I want in within... on the last ADD DELETED LINK HERE.
give the link in the template a class
clone the template
update the div's ID
assign the delIt function to the onclick of the link
give the link a data-delete attribute that references the ID to delete.
insert the clone after the last bank that was inserted
assign the clone as the new "last bank"
var ct = 1;
var tmpl = document.getElementById("newbanktpl");
var lastBank = tmpl;
function new_bank() {
var clone = tmpl.cloneNode(true);
clone.id = "bank_" + ct;
ct++;
var delLink = clone.querySelector(".delete_link");
delLink.setAttribute("data-delete", clone.id);
delLink.onclick = delIt;
lastBank.parentNode.insertBefore(clone, lastBank.nextSibling);
lastBank = clone;
}
// function to delete the newly added set of elements
function delIt() {
var id = this.getAttribute("data-delete");
var ele = document.getElementById(id);
if (ele === lastBank) {
lastBank = ele.previousElementSibling;
}
ele.parentNode.removeChild(ele);
// findTotalA();
}
#newbanktpl {
display: none;
}
<!-- Template -->
<div id="newbanktpl">
<table>
<tr>
<td></td>
<td><textarea name="BankAccount[]"></textarea></td>
<td><input type="number" onblur="findTotalA()" name="Value[]" /></td>
<td><input type="number" name="Ownership[]" /></td>
<td><a class="delete_link" href="#">delete</a></td>
</tr>
</table>
</div>
<button onclick="new_bank()">New Bank</button>
Try adding an id to your td, then you can use it in JS.
In your HTML
<table>
<tr>
...
<td>delete</td>
</tr>
</table>
In your script tag
...
document.getElementById("delete").href="javascript:delIt('+ ct +')";
...
The Entire function should look like this:
var ct = 1;
function new_bank() {
ct++;
var div1 = document.createElement('div');
div1.id = ct;
document.getElementById("delete").href="javascript:delIt('+ ct +')";
document.getElementById('newbank').appendChild(div1);
}
P.S. I don't know why you are trying to save bytes from the computer by calling variables with such short names, it's a waist of your time, it won't make any difference to the computer, but it makes it harder to understand your code.
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.
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 need to get the second td span value based on tr id
`
<table><tr id="1">
<td style="width:150px;"><span id="1">C </span></td>
<td><span style="width:800px;">hello world</span></td>
<td><input type="checkbox" name="1" onclick="KeywordText(1);" value="1"></td>
</tr>
<tr id="2">
<td style="width:150px;"><span id="2">Dot Net </span></td>
<td><span style="width:800px;">Dot Net,java,cobol,hai,Dot Net,java,cobol,hai,Dot Net,java,cobol,hai,Dot Net,java,cobol,hai</span></td>
<td><input type="checkbox" name="2" onclick="KeywordText(2);" value="2"></td>
</tr></table>
This assumes you want the second span
JavaScript:
var row = document.getElementById("rowId");
var spans = row.getElementsByTagName("span");
var secondSpan = spans[1];
jQuery:
var secondSpan = $("#rowId span:eq(1)");
It you want the span inside the second table cell
JavaScript:
var row = document.getElementById("rowId");
var cells = row.getElementsByTagName("td");
var spans = cells.getElementsByTagName("span");
var secondSpan = spans[0];
or with querySelector
var span = document.getElementById("rowId").querySelector("td + td > span");
jQuery:
var secondSpan = $("#rowId td:eq(1) span");
And spans do not have a value, you either what its html or its text.
JavaScript:
var text = secondSpan.innerHTML;
jQuery:
var text = secondSpan.html(); // or secondSpan.text();
function KeywordText(id) {
var td = document.getElementById(id).cells[1];
console.log(td.firstChild.innerHTML); // "hello word" if id == 1
}
example: http://jsfiddle.net/n2t4Z/
Strictly speaking, you can do it like this:
getSpanValueByRowId(1);
function getSpanValueByRowId(rowID) {
var row = document.getElementById(rowID);
var cells = row.getElementsByTagName("td");
var span = cells[1].getElementsByTagName("span")[0];
return span.innerText;
}
Although you could use jQuery to get it, it would look like this:
function getSpanValueByjQuery(rowID){
return $("#"+rowID + " td:nth-child(2) span").text();
}
Using jQuery:
var getvalue=$(this).closest('tr').find('td:eq(1) span').val();
alert(getvalue);