Javascript function to calculate window areas in a table - javascript

I'm just working on a simple calculator for a small project of mine. I'm just hoping to get help with my calculatArea1 function.
I'll attach a few images showing the webpage, html code, and Javascript.
The html starts with a empty row with 3 cells so the user can add in the height and width of the window.
Then, there's a button that allows the user to add a new row/window. This is all working fine.
The problem I'm having is, whenever I add multiple rows, then start adding in the width & height then click calculate it will only calculate the top row.
I though I might add also, if I start fresh with one row, then add the height & width, then click calculate. Then, click add window, then add the width & height, then calculate again. it works.
I just want to be able to add in as many rows as I need, then add in the data, then click calculate.
Any suggestions would be much appreciated, cheers!
HTML
<table id="table1">
<tr>
<th>Height</th>
<th>Width</th>
<th>Area</th>
</tr>
<tr>
<td><input class="height" type="text"></td>
<td><input class="width" type="text"></td>
<td><div class="area"></div></td>
</tr>
</table>
This is my Javascript functions
function addWindow1() {
var table1 = document.getElementById("table1");
var row1 = table1.insertRow(1);
var cell1 = row1.insertCell(0);
var cell2 = row1.insertCell(1);
var cell3 = row1.insertCell(2);
cell1.innerHTML = '<input class="height" type="text">';
cell2.innerHTML = '<input class="width" type="text">';
cell3.innerHTML = '<div class="area"></div>';
};
function calculateArea1() {
var table1 = document.getElementById("table1");
for(var i = 0; row = table1.rows[i]; i++){
var height = document.querySelector('.height').value;
var width = document.querySelector('.width').value;
var area = document.querySelector('.area');
var areaResult = height * width;
area.innerHTML = areaResult;
};
};
This is what happens if I add multiple rows first, then add in the width & height, then click calculate

go to the add window button and add, onclick="addNewWindow()" then add this function
function addNewWindow(){
let table = document.querySelectot('#table1');
let window = `
<tr>
<td><input type="number" class="height"></td>
<td><input type="number" class="width"></td>
<td><input type="number" class="window" disabled style="user-select: select-all"></td>
</tr>
`;
table.insertAdjacentHTML('beforeend', window)
}
then add the calculation functionality
var hinputs = document.querySelectorAll('.height');
var winputs = document.querySelectorAll('.width');
hinputs.foreach(h=>{
h.addEventListener('change', ()=>{
let width = h.parentElement.querySelector('.width');
let window = h.parentElement.querySelector('.window');
if(width.value !== ""){
calculate(width.value, h.value, window )
}
})
})
winputs.foreach(w=>{
w.addEventListener('change', ()=>{
let height = w.parentElement.querySelector('.height ');
let window = w.parentElement.querySelector('.window');
if(height.value !== ""){
calculate(w.value, height.value, window)
}
})
})
function calculate(w, h, result){
result.value = w*h;
}
DEMO:
function addNewWindow() {
let table = document.querySelector('#table');
let window = `
<tr>
<td><input type="number" class="height"></td>
<td><input type="number" class="width"></td>
<td><input type="number" class="window" disabled style="user-select: select-all"></td>
</tr>
`;
table.insertAdjacentHTML('beforeend', window)
}
var hinputs = document.querySelectorAll('.height');
var winputs = document.querySelectorAll('.width');
hinputs.forEach(h => {
h.addEventListener('input', () => {
let width = h.parentElement.parentElement.querySelector('.width');
let window = h.parentElement.parentElement.querySelector('.window');
if (width.value !== "") {
calculate(width.value, h.value, window)
}
})
})
winputs.forEach(w => {
w.addEventListener('input', () => {
let height = w.parentElement.parentElement.querySelector('.height');
let window = w.parentElement.parentElement.querySelector('.window');
if (height.value !== "") {
calculate(w.value, height.value, window)
}
})
})
function calculate(w, h, result) {
result.value = w * h;
}
<table id="table">
<tr>
<td><input type="number" class="height"></td>
<td><input type="number" class="width"></td>
<td><input type="number" class="window" disabled style="user-select: select-all"></td>
</tr>
<tr>
<td><input type="number" class="height"></td>
<td><input type="number" class="width"></td>
<td><input type="number" class="window" disabled style="user-select: select-all"></td>
</tr>
</table>
<button onclick="addNewWindow()">add</button>
you can use ".innerHTML +=" or .insertAdjacentHTML('beforeend', '<div></div>');
but innerHTML removes the old inputs' values because it gets the old value and add to it your code then replace it with the current HTML so all manually applied values get removed, so use inserting beforeend to do it:
let table = document.querySelectot('#table1');
let window = `
<tr>
<td><input type="number" class="height"></td>
<td><input type="number" class="width"></td>
<td><input type="number" class="window" disabled style="user-select: select-all"></td>
</tr>
`;
table.insertAdjacentHTML('beforeend', window)

You are only getting one element with querySelector inside the calculateArea1 function. You should loop over every row and update the area with the values of width and height of that row.
One way to do this is to give a class (lets say data) to rows that contain the width, height and area cells then loop over all elements with that data class and access the cells inside it with a querySelector.
You can simplify your addWindow1 function to this:
function addWindow1() {
const row1 = table1.insertRow(1)
row1.className = 'data'
row1.innerHTML = `
<td><input class="height" type="text" /></td>
<td><input class="width" type="text" /></td>
<td><div class="area"></div></td>
`
}
Then update your calculateArea1 function as follows:
function calculateArea1() {
const data = document.querySelectorAll('.data')
for (let i = 0; i < data.length; i++) {
const height = data[i].querySelector('.height').value
const width = data[i].querySelector('.width').value
data[i].querySelector('.area').textContent = height * width
}
}
Here is a working example:
const add = document.getElementById('add')
const calc = document.getElementById('calc')
const table1 = document.getElementById('table1')
add.addEventListener('click', addWindow1)
calc.addEventListener('click', calculateArea1)
function addWindow1() {
const row1 = table1.insertRow(1)
row1.className = 'data'
row1.innerHTML = `
<td><input class="height" type="text" /></td>
<td><input class="width" type="text" /></td>
<td><div class="area"></div></td>
`
}
function calculateArea1() {
const data = document.querySelectorAll('.data')
for (let i = 0; i < data.length; i++) {
const height = data[i].querySelector('.height').value
const width = data[i].querySelector('.width').value
data[i].querySelector('.area').textContent = height * width
}
}
<button id="add">add</button>
<button id="calc">calc</button>
<table id="table1">
<tr>
<th>Height</th>
<th>Width</th>
<th>Area</th>
</tr>
<tr class="data">
<td><input class="height" type="text" /></td>
<td><input class="width" type="text" /></td>
<td>
<div class="area"></div>
</td>
</tr>
</table>

In the for loop, you should select the width/height from the current row instead of from the DOM.
// select the first item with class `height` in the DOM => not what you want
var height = document.querySelector('.height').value;
// this should work
var height = row.querySelector('.height').value;

Related

Select only checkboxes that are checked in a column

I have an html table that has 5 columns. 2 columns are checkboxes (entry and high) and the other 3 are data. I have 2 buttons, one is called entry and the other high. When a user clicks on the high button, I'm trying to check the column (high) only and get all that is checked, take those values and average them.
The same with entry, when the entry button is clicked, check only the checkboxes in column (entry) and take those values and average them.
So far I have a function to check both columns but not sure how to separately check and separate the columns to each button function only. I have tried the below, but the GetHigh function doesn't work.
Any points in the right direction would be appreciated!
Table
<td><input type="checkbox" class="entry" id="entry" value="{{$sup->entry}}" name="rows[]"></td>
<td><input type="checkbox" class="high" id="high" value="{{$sup->high}}" name="rows[]"></td>
<td><span style="color: #007E33">{{$sup->entry}} </span></td>
<td><span style="color: #007E33">{{$sup->high}} </span></td>
<td><span style="color: #007E33">{{$sup->days}} </span></td>
Buttons
<a href="#here" class="btn btn-primary btn-pill w-10" id="entry" onclick="GetEntry()">
Entry Average
</a>
<a href="#here" class="btn btn-primary btn-pill w-10" id="high" onclick="GetHigh()">
High Average
</a>
Javascript
function GetEntry() {
//Create an Array.
var selected = new Array();
//Reference the Table.
var supTable = document.getElementById("supTable");
//Reference all the CheckBoxes in Table. I WANT ONLY THE ENTRY COLUMN
var entry = supTable.getElementsByTagName("INPUT");
// Loop and push the checked CheckBox value in Array.
for (var i = 0; i < entry.length; i++) {
if (entry[i].checked) {
selected.push(entry[i].value);
}
}
// alert("Average: " + calculate(selected));
$(".text-message").text("Average: " + calculate(selected)).show();
}
function GetHigh() {
//Create an Array.
var selected = new Array();
//Reference the Table.
var supTable = document.getElementById("supTable");
//Reference all the CheckBoxes in Table. I WANT ONLY THE ENTRY COLUMN
var entry = supTable.getElementsByName("High");
// Loop and push the checked CheckBox value in Array.
for (var i = 0; i < high.length; i++) {
if (high[i].checked) {
selected.push(high[i].value);
}
}
// alert("Average: " + calculate(selected));
$(".text-message").text("Average: " + calculate(selected)).show();
}
getElementsByName is used to select HTML where their name="" attribute matches what you've entered, in this case 'High'. But your HTML in the example shows a different name.
You want to use querySelectorAll('high') to get all of the elements that have class="high" set.
You can use a css selector to get the cells of your table
const getCheckboxes = columnIndex =>document.querySelectorAll(`tbody td:nth-child(${columnIndex}) input:checked`);
Or add a common class and select by the class to the checkboxes
const getCheckboxes = className =>document.querySelectorAll(`tbody .${className}:checked`);
Basic example:
const getCheckedCheckboxesClassName = className => document.querySelectorAll(`tbody .${className}:checked`);
const getCheckedCheckboxesByIndex = columnIndex =>document.querySelectorAll(`tbody td:nth-child(${columnIndex}) input:checked`);
const sumValues = cbs => [...cbs].reduce((total, cb) => total + +cb.value, 0);
const getTotal = (group) => {
const cbs = getCheckedCheckboxesClassName(group);
const value = sumValues(cbs);
console.log(value);
}
const getTotalIndex = (index) => {
const cbs = getCheckedCheckboxesByIndex(index);
const value = sumValues(cbs);
console.log(value);
}
<button type="button" onclick="getTotal('low'); getTotalIndex(1)">low</button>
<button type="button" onclick="getTotal('high'); getTotalIndex(2)">high</button>
<table>
<tbody>
<tr>
<td><input class="low" type="checkbox" value="1" /></td>
<td><input class="high" type="checkbox" value="10" /></td>
</tr>
<tr>
<td><input class="low" type="checkbox" value="2" /></td>
<td><input class="high" type="checkbox" value="20" /></td>
</tr>
<tr>
<td><input class="low" type="checkbox" value="3" /></td>
<td><input class="high" type="checkbox" value="30" /></td>
</tr>
<tr>
<td><input class="low" type="checkbox" value="4" /></td>
<td><input class="high" type="checkbox" value="40" /></td>
</tr>
<tr>
<td><input class="low" type="checkbox" value="5" /></td>
<td><input class="high" type="checkbox" value="50" /></td>
</tr>
</tbody>
</table>

Rewriting JavaScript code with consequent numbers in the names of ids

I'm trying to apply a function to input field with ids that contain consequent numbers (ie. price1, price2, price3), etc.
There's no problem with the first row of field that are defined for a start. But further input fields are dynamically added by a jQuery function and their number is not known in advance.
I hoped it would be an easy loop to apply:
var i=1;
$("#quantity"+i).keyup(function() {
var price= $("#price"+i).val();
var quantity= $(this).val();
var value= price*quantity;
var value=value.toFixed(2); /* rounding the value to two digits after period */
value=value.toString().replace(/\./g, ',') /* converting periods to commas */
$("#value"+i).val(value);
});
So far so good - the outcome of the multiplication properly displays in the id="value1" field after the "quantity" field is filled up.
Now further fields should follow the pattern and calculate the value when the quantity is entered - like this:
[price2] * [quantity2] = [value2]
[price3] * [quantity3] = [value3]
etc.
So the code follows:
$('#add_field').click(function(){ /* do the math after another row of fields is added */
var allfields=$('[id^="quantity"]');
var limit=(allfields.length); /* count all fields where id starts with "quantity" - for the loop */
for (var count = 2; count < limit; count++) { /* starting value is now 2 */
$("#quantity"+count).keyup(function() {
var cena = $("#price"+count).val();
var quantity= $("#quantity"+count).val();
var value= price*quantity;
var value=value.toFixed(2);
value=value.toString().replace(/\./g, ',')
$("#value"+count).val(value);
});
}
});
The problem is that all further "value" fields are only calculated when "quantity2" is (re)entered and the "value2" is not calculated at all.
I guess there's a mistake while addressing fields and/or triggering the calculation.
How should I correct the code?
Just in case the "add_field" function is needed to solve the problem:
$(document).ready(function(){
var i=1;
$('#add_field').click(function(){
i++;
$('#offer').append('<tr id="row'+i+'">
<td><input type="text" name="prod_num[]" id="prod_num'+i+'" placeholder="Product number (6 digits)"></td><td><input type="text" name="prod_name[]" disabled></td>
<td><input type="text" name="cena[]" id="price'+i+'" placeholder="Enter your price"></td>
<td><input type="text" name="quantity[]" id="quantity'+i+'" placeholder="Enter quantity"></td>
<td><input type="text" name="value[]" id="value'+i+'" disabled></td>
<td><button type="button" name="remove_field" id="'+i+'" class="button_remove">X</button></td></tr>');
});
Incrementing IDs is a lot more trouble than it is worth, especially when you start removing rows as well as adding them.
This can all be done using common classes and traversing within the specific row instance.
To account for future rows use event delegation.
Simplified example:
// store a row copy on page load
const $storedRow = $('#myTable tr').first().clone()
// delegate event listener to permanent ancestor
$('#myTable').on('input', '.qty, .price', function(){
const $row = $(this).closest('tr'),
price = $row.find('.price').val(),
qty = $row.find('.qty').val();
$row.find('.total').val(price*qty)
});
$('button').click(function(){
// insert a copy of the stored row
// delegated events will work seamlessly on new rows also
const $newRow = $storedRow.clone();
const prodName = 'Product XYZ';// get real value from user input
$newRow.find('.prod-name').text(prodName)//
$('#myTable').append($newRow)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>Add row</button>
<table id="myTable">
<tr>
<td class="prod-name">Product 1</td>
<td>Qty:<input type="number" class="qty" value="0"></td>
<td>Price:<input type="number" class="price" value="0"></td>
<td>Total:<input type="text" class="total" value="0" readonly></td>
</tr>
<tr>
<td class="prod-name">Product 2</td>
<td>Qty:<input type="number" class="qty" value="0"></td>
<td>Price:<input type="number" class="price" value="0"></td>
<td>Total:<input type="text" class="total" value="0" readonly></td>
</tr>
</table>
Understanding Event Delegation
The first thing to consider is that you can get the length of a selector. So for example:
var count = $("input").length;
If there is one, value here would be 1. if there are four, the value would be 4.
You can also use .each() option to itereate each of the items in the selector.
$('#add_field').click(function(){
var allFields = $('[id^="quantity"]');
allFields.each(function(i, el){
var c = i + 1;
$(el).keyup(function() {
var price = parseFloat($("#price" + c).val());
var quantity = parseInt($(el).val());
var value = price * quantity;
value = value.toFixed(2);
value = value.toString().replace(/\./g, ',');
$("#value" + c).val(value);
});
});
});
You could also create relationship based on the ID itself.
$(function() {
function calcTotal(price, qnty) {
return (parseFloat(price) * parseInt(qnty)).toFixed(2);
}
$('#add_field').click(function() {
var rowClone = $("#row-1").clone(true);
var c = $("tbody tr[id^='row']").length + 1;
rowClone.attr("id", "row-" + c);
$("input:eq(0)", rowClone).val("").attr("id", "prod_num-" + c);
$("input:eq(1)", rowClone).val("").attr("id", "price-" + c);
$("input:eq(2)", rowClone).val("").attr("id", "quantity-" + c);
$("input:eq(3)", rowClone).val("").attr("id", "value-" + c);
$("button", rowClone).attr("id", "remove-" + c);
rowClone.appendTo("table tbody");
});
$("table tbody").on("keyup", "[id^='quantity']", function(e) {
var $self = $(this);
var id = $self.attr("id").substr(-1);
if ($("#price-" + id).val() != "" && $self.val() != "") {
$("#value-" + id).val(calcTotal($("#price-" + id).val(), $self.val()));
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="add_field">Add Field</button>
<br />
<h2>Product</h2>
<table>
<thead>
<tr>
<td>Number</td>
<td>Name</td>
<td>Price</td>
<td>Quantity</td>
<td>Total</td>
<td></td>
</thead>
<tbody>
<tr id="row-1">
<td><input type="text" name="prod_num[]" id="prod_num-1" placeholder="Product number (6 digits)"></td>
<td><input type="text" name="prod_name[]" disabled></td>
<td><input type="text" name="cena[]" id="price-1" placeholder="Enter your price"></td>
<td><input type="text" name="quantity[]" id="quantity-1" placeholder="Enter quantity"></td>
<td><input type="text" name="value[]" id="value-1" disabled></td>
<td><button type="button" name="remove_field" id="remove-1" class="button_remove">X</button></td>
</tr>
</tbody>
</table>

Making a for loop to calculate specific cells then writing result in the last cell in row

I'm very new to JS and I'm trying to learn for loops and in this case, I want to turn this into a for loop if possible. I want to calculate a static number string in cell 3, times the input number in cell 4, and output the result to a new cell 5 that has been created in the loop. Any help is much appreciated
var table = document.getElementById("table");
var Row1 = table.rows[1],
cell1 = Row1.insertCell(5);
var Row2 = table.rows[2],
cell2 = Row2.insertCell(5);
var Row3 = table.rows[3],
cell3 = Row3.insertCell(5);
var Row4 = table.rows[4],
cell4 = Row4.insertCell(5);
var Row5 = table.rows[5],
cell5 = Row5.insertCell(5);
var Row6 = table.rows[6],
cell6 = Row6.insertCell(5);
var x1 = table.rows[1].cells[4].getElementsByTagName('input')[0].value;
var y1 = table.rows[1].cells[3].innerHTML;
cell1.innerHTML = y1 * x1;
var x2 = table.rows[2].cells[4].getElementsByTagName('input')[0].value;
var y2 = table.rows[2].cells[3].innerHTML;
cell2.innerHTML = y2 * x2;
var x3 = table.rows[3].cells[4].getElementsByTagName('input')[0].value;
var y3 = table.rows[3].cells[3].innerHTML;
cell3.innerHTML = y3 * x3;
var x4 = table.rows[4].cells[4].getElementsByTagName('input')[0].value;
var y4 = table.rows[4].cells[3].innerHTML;
cell4.innerHTML = y4 * x4;
var x5 = table.rows[5].cells[4].getElementsByTagName('input')[0].value;
var y5 = table.rows[5].cells[3].innerHTML;
cell5.innerHTML = y5 * x5;
var x6 = table.rows[6].cells[4].getElementsByTagName('input')[0].value;
var y6 = table.rows[6].cells[3].innerHTML;
cell6.innerHTML = y6 * x6;
These don't need to be in functions but just to make it easier to read
function createCells() {
cells = []
for (let i = 1; i < 7; i++) {
var cells[i] = table.rows[i].insertCell(5)
}
}
function calculate() {
for
let (i = 1; i < 7; i++) {
var x = table.rows[i].cells[4].getElementsByTagName('input')[0].value;
var y = table.rows[i].cells[3].innerHTML;
cells[i].innerHTML = (y * x);
}
}
A short answer using a simple for-loop is this:
Loop through every row
For each row, multiply quantity with price
Output total in same row
Since we basically always want to have a "total"-field in every row, we can add it in the HTML directly.
And since we know the position of the price-element and quantity-element, we can access them using fixed values as indices.
var rows = document.querySelectorAll("#pricetable tbody tr");
for (var i = 0; i < rows.length; ++i) {
var price = rows[i].children[3].innerHTML;
var quantity = rows[i].children[4].children[0].value;
var total = price * quantity; // Implicit type-casting to numbers
rows[i].children[5].innerHTML = total;
}
<table id="pricetable">
<thead>
<tr>
<th>Number</th>
<th>Product</th>
<th>Brand</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td>23456789</td>
<td>Phone</td>
<td>Apple</td>
<td>6500</td>
<td>
<input type="text" size="3" value="1" />
</td>
<td></td>
</tr>
<tr>
<td>22256289</td>
<td>Phone</td>
<td>Samsung</td>
<td>6200</td>
<td>
<input type="text" size="3" value="1" />
</td>
<td></td>
</tr>
<tr>
<td>24444343</td>
<td>Phone</td>
<td>Huawei</td>
<td>4200</td>
<td>
<input type="text" size="3" value="1" />
</td>
<td></td>
</tr>
<tr>
<td>19856639</td>
<td>Tablet</td>
<td>Apple</td>
<td>4000</td>
<td>
<input type="text" size="3" value="1" />
</td>
<td></td>
</tr>
<tr>
<td>39856639</td>
<td>Tablet</td>
<td>Samsung</td>
<td>2800</td>
<td>
<input type="text" size="3" value="1" />
</td>
<td></td>
</tr>
<tr>
<td>12349862</td>
<td>Tablet</td>
<td>Huawei</td>
<td>3500</td>
<td>
<input type="text" size="3" value="1" />
</td>
<td></td>
</tr>
</tbody>
</table>
Note: When changing the position of those elements (e.g. by add a new column infront of them), their index would shift. That would make you have to update the indices in the JS-file manually.
You can make this easier for yourself by using this simple "trick":
Add specific classes to the elements (e.g. .price, .quantity, .total), allowing you to easily find them using Element.querySelector().
Note: The script only runs once, the first time the page is loaded. That means, inputting a different quantity won't update the "total"-field. For that, we need an EventListener.
Another approach
By observing the for-loop, we can see:
We access only one row for each iteration
The order in which we access each row is irrelevant
Since both these points are checked, we can use a for...of-loop (also called foreach-loop or enhanced for-loop). A for...of-loop is (in my opinion) easier to read, and tells what we checked using the list above by itself.
Note: Be wary of the difference of the for...of-loop and the for...in-loop.
Now, we could calculate the total right then and there in the loop, but thinking ahead, we want to perform the same calculation again when inputting a new quantity-value. We can reduce the duplicate code by making the calculation a Function updateRowTotal(), making the code easier to debug and understand.
To actually update the total when entering a new quantity-value, we can use an EventListener that calls a function automatically when a new value is entered into the <input>-field (by calling updateRowTotal(evt.target.closest("tr"))).
function clamp(min, value, max) {
return Math.max(min, Math.min(value, max));
}
for (let row of document.querySelectorAll("#pricetable tbody tr")) {
updateRowTotal(row);
row.querySelector("input.quantity").addEventListener("input", evt => {
// Add '/*' before this comment to "remove" this extra part
// The 5 lines below are to clamp 'value' between 'min' and 'max'
let min = parseInt(evt.target.getAttribute("min"));
let max = parseInt(evt.target.getAttribute("max"));
if (isNaN(min)) min = Number.MIN_SAFE_INTEGER;
if (isNaN(max)) max = Number.MAX_SAFE_INTEGER;
evt.target.value = clamp(min, evt.target.value, max);
// */
updateRowTotal(evt.target.closest("tr"));
});
}
function updateRowTotal(row) {
row.querySelector(".total").innerHTML = row.querySelector(".price").innerHTML * row.querySelector(".quantity").value;
}
<table id="pricetable">
<thead>
<tr>
<th>Price</th>
<th>Quantity</th>
<th>Row-Total</th>
</tr>
</thead>
<tbody>
<tr>
<td class="price">6500</td>
<td>
<input class="quantity" type="number" min="0" max="999" value="1" />
</td>
<td class="total"></td>
</tr>
<tr>
<td class="price">6200</td>
<td>
<input class="quantity" type="number" min="0" max="999" value="1" />
</td>
<td class="total"></td>
</tr>
<tr>
<td class="price">4200</td>
<td>
<input class="quantity" type="number" min="0" max="999" value="1" />
</td>
<td class="total"></td>
</tr>
<tr>
<td class="price">4000</td>
<td>
<input class="quantity" type="number" min="0" max="999" value="1" />
</td>
<td class="total"></td>
</tr>
<tr>
<td class="price">2800</td>
<td>
<input class="quantity" type="number" min="0" max="999" value="1" />
</td>
<td class="total"></td>
</tr>
<tr>
<td class="price">3500</td>
<td>
<input class="quantity" type="number" min="0" max="999" value="1" />
</td>
<td class="total"></td>
</tr>
</tbody>
</table>
Sidenote
Making the <input>-field of type="number" prevents any non-numeric character to be entered.
And since the min- and max-attributes only prevent form-submission, we have to code the value-clamping ourselves. This is easily done by reading the values of the attributes and clamping the value to their defined range. Note that we have added default values for both min and max, being the lower-most and upper-most safe integer-value.
You can use for-loops like the one given below. Looks like you are operating on numbers, so I have added a + in front of x1's and y1's assignment to implicitly type-cast them to numbers.
for(var i = 1; i <= 6; i++) {
var firstRow = table.rows[i], cell = firstRow.insertCell(5);
var x1 = +table.rows[i].cells[4].getElementsByTagName('input')[0].value;
var y1 = +table.rows[i].cells[3].innerHTML;
cell.innerHTML = y1 * x1;
}

JavaScript calculated field

I just can't see what am I doing wrong... It doesn't calculate the "stunden" field.
There is some small mistake from my side and I just can't see it.
EDITED: now all is working as it should
$(document).ready(function(){
$('.item').keyup(function(){
var starts = 0;
var ends = 0;
var stunden = 0;
if (!isNaN($(this).find(".starts").val())) {
starts = $(this).find(".starts").val();
}
if (!isNaN($(this).find(".ends").val())) {
ends = $(this).find(".ends").val();
}
stunden = ends - starts;
$(this).find(".stunden").val(stunden);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<table id="t1" class="table table-hover">
<tr>
<th class="text-center">Start Time</th>
<th class="text-center">End Time</th>
<th class="text-center">Stunden</th>
</tr>
<tr id="row1" class="item">
<td><input name="starts[]" class="starts form-control" ></td>
<td><input name="ends[]" class="ends form-control" ></td>
<td><input name="stunden[]" class="stunden form-control" readonly="readonly" ></td>
</tr>
<tr id="row2" class="item">
<td><input name="starts[]" class="starts form-control" ></td>
<td><input name="ends[]" class="ends form-control" ></td>
<td><input name="stunden[]" class="stunden form-control" readonly="readonly" ></td>
</tr>
</table>
</div>
The problem is that you are recalculating when a key is pressed in the .stunden fields, so you should move the event to the other inputs, or the parent row. You'll need something like this.
$('.item').keyup(function(){
var starts = 0;
var ends = 0;
var stunden = 0;
if (!isNaN($(this).find(".starts").val())) {
starts = $(this).find(".starts").val();
}
if (!isNaN($(this).find(".ends").val())) {
ends = $(this).find(".ends").val();
}
stunden = starts - ends;
$(this).find(".stunden").val(stunden);
});
Let me try your original keyup code .ends ,I just want to explain how is work below code
call .starts ,we currently in tr>td>input ,so need backup to tr by parent() then we find .starts inside its elements.As also .ends
find .studen is also in state tr>td>input ,so backup to td and go next td by next() then find .studen .
$(document).ready(function(){
$('.ends').keyup(function(){
var starts = 0;
var ends = 0;
var stunden = 0;
if (!isNaN($(this).parent().parent().find(".starts").val())) {
starts = $(this).parent().parent().find(".starts").val();
}
if (!isNaN($(this).parent().parent().find(".ends").val())) {
ends = $(this).parent().parent().find(".ends").val();
}
stunden = starts - ends;
$(this).parent().next().find('.stunden').val(stunden);
});
});

adding values to unknown element ids in jquery

I have a dynamically created form in that a user can click "add row" and get a new element in the form.
some of the elements are quantity and price. I want to change values based on what users enter. so if he chooses qty=4 and price=10 i want amount to =40.
I dont know what to use as the selector for price or amount since input ids are dynamically generated.
var form = "<tr><td>Quantity</td>
<td><input class='qty' type='text' id='qty[]' name='qty[]'></td>";
form += "<td>Part Num</td>
<td><input type='text' id='part[]' name='part[]'></td>";
form += "<td>Description</td>
<td><input class='desc' type='text' id='desc[]' name='desc[]'></td>";
form += "<td>Unit Price</td>
<td><input type='text' id='price[]' name='price[]'></td>";
form += "<td>Amount</td>
<td><input type='text' id='amount[]' name='amount'></td></tr>";
$('#addItem').click(function(){
$('#itemsTable').append(form);
});
$(document).on('change','.qty',function(){
//What can i use as a selector for value_of_qty and value_of_price here???
//var total = $(value_of_qty) * $(value_of_price);
//$(id_of_amount).val(total);
});
on form submissions i see the following:
[qty] => Array
(
[0] => asdfdasf
[1] => asdfdasf
)
and so on....
You have (roughly) this structure:
<tr>
<td><input class="qty"></td>
<td><input name="price[]"></td>
</tr>
So, given that you have the .qty input, all you need to do is rise to the tr and get its input[name='price[]']. In code:
$(document).on('change','.qty',function(){
var $qty = $(this);
var $price = $qty.closest("tr").find("input[name='price[]']");
});
As I described in my comment, your HTML is invalid because you have duplicate ids. You should dynamically generate the HTML you append to the parent element, and assign a unique id value with each appendage. Here's what I would do:
var g_ROWNUM = 1;
$('#addItem').click(function() {
var form = '\
<tr>\
<td>Quantity</td><td><input class="qty" type="text" id="qty_${num}" name="qty[]"></td>\
<td>Part Num</td><td><input type="text" id="part_${num}" name="part[]"></td>\
<td>Description</td><td><input class="desc" type="text" id="desc_${num}" name="desc[]"></td>\
<td>Unit Price</td><td><input type="text" id="price_${num}" name="price[]"></td>\
<td>Amount</td><td><input type="text" id="amount_${num}" name="amount[]"></td>\
</tr>\
'.replace(/\$\{num\}/g,g_ROWNUM++);
$('#itemsTable').append(form);
});
$(document).on('change', '.qty', function() {
var qtyInput = $(this);
var num = qtyInput.attr('id').replace(/^qty_/,'');
var priceInput = $('#price_'+num);
var amountInput = $('#amount_'+num);
var total = qtyInput.val()*priceInput.val();
amountInput.val(total);
});
As you can see, this allows you to extract the generated number and use it to retrieve the price and amount elements in the same row as the changed quantity element, and then apply any dynamic changes you want to the elements in that row.
http://jsfiddle.net/p6wrkne4/1/
you should restructure your html by adding classes like this:
<tr class="tableRow">
<td>Quantity</td>
<td><input class='qty' type='text' id='qty[]' name='qty[]'/></td><td>Part Num</td>
<td><input type='text' id='part[]' name='part[]'/></td>
<td>Description</td>
<td><input class='desc' type='text' id='desc[]' name='desc[]'/></td>
<td>Unit Price</td>
<td><input type='text' class="price" id='price[]' name='price[]'/></td>
<td>Amount</td>
<td><input type='text' class="amount" id='amount[]' name='amount'/></td>
</tr>
$(document).on('change', '.qty', function() {
var qty = $(this).val();
var price = $(this).closest('.tableRow').find('.price').val();
var total = qty * price;
$(this).closest('.tableRow').find('.amount').val(total);
});
Try this code:
$(document).on('change','.qty',function(){
var qtyInput = $(this);
var price = qtyInput.closest("tr").find("input[name='price[]']").val();
var amount = qtyInput.val() * price;
qtyInput.closest("tr").find("input[name=amount]").val(amount);
});

Categories

Resources