jQuery dynamic content calculate - javascript

My code is working perfectly with static part, but when i add a new row it won't calculate the field. What am i doing wrong?
It should calculate also the dynamic fields which are added via Add Row button
Live DEMO
<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>
<th> <button type="button" class="addRow">Add Row</button></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>
</table>
</div>
js
$(document).ready(function(){
$('.item').keyup(function(){
var starts = $(this).find(".starts").val();
var ends = $(this).find(".ends").val();
var stunden;
s = starts.split(':');
e = ends.split(':');
min = e[1]-s[1];
hour_carry = 0;
if(min < 0){
min += 60;
hour_carry += 1;
}
hour = e[0]-s[0]-hour_carry;
min = ((min/60)*100).toString()
stunden = hour + "." + min.substring(0,2);
$(this).find(".stunden").val(stunden);
});
// function for adding a new row
var r = 1;
$('.addRow').click(function () {
if(r<10){
r++;
$('#t1').append('<tr id="row'+ r +'" 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>');
}
});
// remove row when X is clicked
$(document).on("click", ".btn_remove", function () {
r--;
var button_id = $(this).attr("id");
$("#row" + button_id + '').remove();
});
});

The best thing would be to use the .on() event which is used to attach one or more event handlers to the element:
$(document).on('keyup', '.item',function(){
//your code
}

When you dynamically add a new row to your table, the "keyup" event wont automatically be bound to it. Essentially you need to wrap the "keyup" event binding into a function, then call it after you've added the new row on. Something along the lines of:
function rebindKeyup(){
$('.item').keyup(function(){
// Key up logic
}
}

Related

Jquery UI sortable not working for appended rows

I am trying to use jQuery UI to make a sortable table. It is working fine for the rows already added before the page load. However, I also have function to let users to add new rows, if they need.
jQuery UI sortable function not working for these appended rows.
HTML:
<button id="add" onclick="cloneRow()">Add row(s)</button>
<table id="testTable" class="table">
<thead>
<tr>
<th></th>
<th>Column 1</th>
<th>Column 2</th>
</tr>
</thead>
<tbody>
<tr id="rowFirst">
<td>#</td>
<td><input class="form-control" type="text" name="c1[]"></td>
<td><input class="form-control" type="text" name="c2[]"></td>
</tr>
<tr>
<td>#</td>
<td><input class="form-control" type="text" name="c1[]"></td>
<td><input class="form-control" type="text" name="c2[]"></td>
</tr>
</tbody>
</table>
JS:
function cloneRow() {
var rowAmount = document.getElementById("rowAmount").value;
var getTotalRows = $('table > tbody').children().length;
for (var i = -1; i < rowAmount - 1; i++) {
var row = document.getElementById("rowFirst"); // find row to copy
var table = document.getElementById("testTable"); // find table to append to
var clone = row.cloneNode(true); // copy children too
clone.id = "newRow" + (getTotalRows + i); // change id or other attributes/contents
clone.classList.remove('hidden');
table.appendChild(clone); // add new row to end of table
$('#newRow' + (getTotalRows + i)).children().each(function() {
$(this).children().attr('id', $(this).children().attr('id') + (getTotalRows + i));
});
}
}
$("table tbody").sortable({});
https://jsfiddle.net/brkztrk/3odnr4t2/5/
As you can see first two rows are perfectly sortable, but rows appended by cloneRow() function are not sortable.
does anybody has any idea how to fix this?
Thanks a lot!
Consider the following: https://jsfiddle.net/Twisty/srm7fyo3/
JavaScript
function cloneRow() {
var rowAmount = $("#rowAmount").val();
for (var i = 0; i <= rowAmount; i++) {
var clone = $("#rowFirst").clone();
clone.attr("id", "new-row-" + $('table > tbody > tr').length);
clone.appendTo("table tbody");
$("table tbody").sortable("refresh");
}
}
$("table tbody").sortable({
items: "> tr",
handle: "td:eq(0)"
});
As new rows are created, the Sortable is refreshed. This way they each become a sortable item.

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>

How to copy the value from one input box to another input box?

By clicking on Add New Row button, new input boxes can be generated. I want to copy the value from one input box (First column - Hours ) to another input box (Second Column - In Office).
Screenshot:
First Row: Value is copied from one input box to another input box when it is a static element. Here input box is created by HTML.
Dynamic Rows: Value is not copied from one input box to another input box when it is a dynamic element. Here input box is created by JavaScript.
Issue:
Value is not copied because the elements are generated dynamically with same id and name
What I tried:
$(document).ready(function() {
$('[data-toggle="tooltip"]').tooltip();
var actions = $("table td:last-child").html();
// Append table with add row form on add new button click
$(".add_new").click(function() {
var index = $("table tbody tr:last-child").index();
var row = '<tr>' +
'<td><input type="number" name="hours[]" id="hours"></td>' +
'<td><input type="number" name="inoffice[]" id="inoffice"></td>' +
'</tr>';
$("table").append(row);
$('[data-toggle="tooltip"]').tooltip();
});
// Add row on add button click
$(document).on("click", ".add", function() {
var empty = false;
var input = $(this).parents("tr").find('input[type="text"]');
input.each(function() {
if (!$(this).val()) {
$(this).addClass("error");
empty = true;
} else {
$(this).removeClass("error");
}
});
$(this).parents("tr").find(".error").first().focus();
if (!empty) {
input.each(function() {
$(this).parent("td").html($(this).val());
});
}
});
});
function sync() {
var hours = document.getElementById('hours');
var inoffice = document.getElementById('inoffice');
inoffice.value = hours.value;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<table class="table table-bordered">
<thead>
<tr>
<th>Hours</th>
<th>In Office</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="number" name="hours[]" id="hours" onkeyup="sync()" onClick="sync()"></td>
<td><input type="number" name="inoffice[]" id="inoffice"></td>
</tr>
</tbody>
</table>
<input type="button" id="add_new" name="add_new" class="add_new" value="Add New Row">
You should not be duplicating id attributes as it's invalid HTML and will lead to other issues. Use class attributes instead to group elements by common behaviour patterns.
From there you can use a delegated event handler to handle all the .hours elements that will ever exist in the DOM.
Also note that inline event attributes are outdated and should be avoided where possible.
$('table').on('input', '.hours', function() {
$(this).closest('tr').find('.inoffice').val(this.value);
});
$(document).ready(function() {
$('[data-toggle="tooltip"]').tooltip();
var actions = $("table td:last-child").html();
$(".add_new").click(function() {
var index = $("table tbody tr:last-child").index();
var row = '<tr>' +
'<td><input type="number" name="hours[]" class="hours"></td>' +
'<td><input type="number" name="inoffice[]" class="inoffice"></td>' +
'</tr>';
$("table").append(row);
$('[data-toggle="tooltip"]').tooltip();
});
$(document).on("click", ".add", function() {
var empty = false;
var input = $(this).parents("tr").find('input[type="text"]');
input.each(function() {
if (!$(this).val()) {
$(this).addClass("error");
empty = true;
} else {
$(this).removeClass("error");
}
});
$(this).parents("tr").find(".error").first().focus();
if (!empty) {
input.each(function() {
$(this).parent("td").html($(this).val());
});
}
});
$('table').on('input', '.hours', function() {
$(this).closest('tr').find('.inoffice').val(this.value);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<table class="table table-bordered">
<thead>
<tr>
<th>Hours</th>
<th>In Office</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="number" name="hours[]" class="hours"></td>
<td><input type="number" name="inoffice[]" class="inoffice"></td>
</tr>
</tbody>
</table>
<input type="button" id="add_new" name="add_new" class="add_new" value="Add New Row">
Start by creating an MCVE. That means remove all the code that isn't part of the problem. This will make everything clearer.
Remove IDs, since IDs must be unique, we better use classes instead.
$(document).ready(function() {
$(".add_new").click(function() {
var index = $("table tbody tr:last-child").index();
var row = '<tr>' +
'<td><input type="number" name="hours[]" class="hours"></td>' +
'<td><input type="number" name="inoffice[]" class="inoffice"></td>' +
'</tr>';
$("table").append(row);
$('[data-toggle="tooltip"]').tooltip();
});
});
$(document).on("keyup", ".hours", function(){
$(this).parent().parent().find(".inoffice").val(this.value);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<table class="table table-bordered">
<thead>
<tr>
<th>Hours</th>
<th>In Office</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="number" name="hours[]" class="hours"></td>
<td><input type="number" name="inoffice[]" class="inoffice"></td>
</tr>
</tbody>
</table>
<input type="button" id="add_new" name="add_new" class="add_new" value="Add New Row">

Adding more values from another field with JavaScript

Need help to solve a JavaScript problem.
i am working on an invoice in which i want to add more values to quantity field.
i am trying with script given in JSFiddle.
The problem is when i click on edit , it should popup a dialog box and by entering data in add field it should be added to current quantity of a specific item.
https://jsfiddle.net/programmer/LLmrp94y/16/
JS script
$(document).on('change', '.addQty', function () {
id_arr = $(this).attr('id');
id = id_arr.split("_");
add = $('#add_'+id[1]).val();
qty = $('#quantity_'+id[1]).val();
if (add != '' && typeof (add) != "undefined") {
$('#add_'+id[1]).val();
added = parseFloat(qty) + parseFloat(add);
$('#qtY_'+id[1]).val(added);
priceAfter = $('#price_'+id[1]).val();
$('#Total_'+id[1]).val((parseFloat(priceAfter) * parseFloat(added)).toFixed(2));
} else {
$('#quantity_'+id[1]).val(qty);
$('#Total_'+id[1]).val((parseFloat(price) * parseFloat(qty)).toFixed(2));
}
});
I made it work by doing the following :
adding an id to your edit buttons, so we can retrieve the id of the line currently being edited
replacing your 'onchange' function by a addQuantity function that takes a parameter : the id of the line being edited.
fixing a couple issues with the ids used in the code written to calculate the new quantity and the new price
Also, I replaced your php code by hard coded ids. You're going to have to replace them.
EDIT : Since you don't want to show the current quantity in the dialog, I had to change the logic and update the table after close has been clicked. Otherwise it caused too many issues. Hope you like it.
$(document).ready(function() {
calculateEachItemSubCost();
});
function calculateEachItemSubCost() {
var qtys = document.getElementsByClassName('quantity');
var price = document.getElementsByClassName('price');
var item_costs = document.getElementsByClassName('totalLinePrice');
for (var i = 0; i < item_costs.length; ++i) {
item_costs[i].value = parseFloat(qtys[i].value) * parseFloat(price[i].value).toFixed(2);
}
}
/* new function that replaces your 'onchange' listener. It handles the adding of a quantity on a given line, identified by the id parameter */
function addQuantity(id) {
var add, added, priceAfter;
add = $('#addedQuantity').val();
console.log("Adding " + add + " on line " + id);
if (add != '' && typeof add != "undefined") {
;
added = parseInt($('.add').val()) + parseInt($('#quantity_' + id).val())
$('#quantity_' + id).val(added);
priceAfter = $('#price_' + id).val();
$('#total_' + id).val((parseFloat(priceAfter) * parseFloat(added)).toFixed(2));
} else {
$('#quantity_' + id).val(qty);
$('#Total_' + id).val((parseFloat(price) * parseFloat(qty)).toFixed(2));
}
}
$(document).on('click', '.editnow', function(event) {
var lineId, quantityField;
// retrieving the id of the line that was clicked on
lineId = event.target.id.split("_")[1];
quantityField = $("#quantity_" + lineId);
$(".add").val("");
$("#edit").dialog({
show: "fold",
hide: "fold",
modal: true,
title: "Edit",
zIndex: 10000,
close: function(event, ui) {
addQuantity(lineId);
$(this).hide();
}
});
});
#edit{
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/ui-lightness/jquery-ui.css"/>
<!DOCTYPE html>
<!-- Begin page content -->
<h1 class="text-center title">Invoice</h1>
<table>
<thead>
<tr>
<th width="38%">Item Name</th>
<th width="15%">Price</th>
<th width="15%">Quantity</th>
<th width="15%">Total</th>
<th width="15%">Edit</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" value="samsung galaxy s6" id="itemName_1" ></td>
<td><input type="number" value="500" id="price_1" class="price"></td>
<td><input type="number" value="1" id="quantity_1" class="quantity"></td>
<td><input type="number" value="" id="total_1" class="totalLinePrice"></td>
<td><button type="button" class="editnow" id="edit_1"> Edit </button></td>
</tr>
<tr>
<td><input type="text" value="samsung galaxy s7" id="itemName_2" ></td>
<td><input type="number" value="700" id="price_2" class="price"></td>
<td><input type="number" value="1" id="quantity_2" class="quantity"></td>
<td><input type="number" value="" id="total_2" class="totalLinePrice"></td>
<td><button type="button" class="editnow" id="edit_2"> Edit </button></td>
</tr>
</tbody>
</table>
<div id="edit">
<table>
<tr>
<th>Add</th>
</tr>
<tr>
<td><input type="number" class="add" id="addedQuantity"></td>
</tr>
</table>
</div>
Your updated JSFiddle
I have edited it, but it does not work because of the php values not working, of course. I've added id to Edit buttons, and getting value from dialog. Based on the button id, you can enter value to corresponding quantity field
<button type="button" id="edit_<?php $i; ?>" class="editnow"> Edit </button>
Yes: function () {
var id = $(this).attr('id');
id = id.substring(id.indexOf('_')+1);
alert($('#quantityVal').val()); // just check the value
$('#quantity_'+id).val($('#quantityVal').val());
$(this).dialog("close");
},
Edit dialog number field
<td><input type="number" class="add" id="quantityVal"></td>
https://jsfiddle.net/LLmrp94y/12/

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);
});
});

Categories

Resources