Loop through each table row to perform math operation - javascript

I have the below jquery add table
$(document).on('click', '.add', function(){
var html = '';
html += '<tbody><tr>';
html += '<td><select name="product_name[]" class="pu-input product_name">
<option value="">--Select--</option><?php echo
fill_unit_select_box($connect); ?></select></td>';
html += '<td><input type="text" name="mt[]" class="pu-input mt" id="mt"/>
</td>';
html += '<td><input type="text" name="ream[]" class="pu-input ream"></td>';
html += '<td><input type="text" name="unit_price[]" class="pu-input
unit_price" id="price"></td>';
html += '<td><input type="text" name="d_price[]" class="pu-input d_price"
id="discount"></td>';
html += '<td><input type="text" name="td_price[]" class="pu-input td_price"
id="total_dis"></td>';
html += '<td><input type="text" name="vat[]" class="pu-input vat" id="vat">
</td>';
html += '<td><input type="text" name="t_vat[]" class="pu-input t_vat"
id="t_vat"></td>';
html += '<td><input type="text" name="total[]" class="pu-input total"
id="total"></td>';
html += '<td><button type="button" name="remove" class="btn btn-danger btn-
sm remove"><i class="fas fa-minus"></i></span></button></td></tr></tbody>';
$('#item_table').append(html);
$('tr').each(function(){
$('input').keyup(function(){ // run anytime the value changes
var mt = Number($('#mt').val()); // get value of field
var price = Number($('#price').val()); // convert it to a float
var discount = Number($('#discount').val());
var vat = Number($('#vat').val());
document.getElementById('total').value = mt * price;
document.getElementById('total_dis').value = mt * discount;
document.getElementById('t_vat').value = mt * vat;
// add them and output it
});
});
what I want to do is loop through each table row and perform a math function against two inputs, and populate the result into a third input.
but the problem is that the math functions are only working on the first row not working in the further rows.
enter image description here

As has been mentioned in the comments, HTML element ids are meant to be unique. If you are not going to assign unique ids when you create the rows (say, with a counter that you increment each time), then you are better off just omitting the element ids.
Second, there is no need to create/assign event handlers each time you add a new row. Instead, take advantage of delegated event handling. Remove your $('tr').each(function(){ entirely and instead, outside of your row adding code, put this:
$('table').on('keyup', 'input', function(){ // run anytime the value changes
$thisRow = $(this).parent().parent();console.log($thisRow.find('td>.total'));
var mt = Number($thisRow.find('td>.mt').val()); // get value of field
var price = Number($thisRow.find('td>.unit_price').val()); // convert it to a float
var discount = Number($thisRow.find('td>.d_price').val());
var vat = Number($thisRow.find('td>.vat').val());
$thisRow.find('td>.total').val(mt * price);
$thisRow.find('td>.td_price').val(mt * discount);
$thisRow.find('td>.t_vat').val(mt * vat);
// add them and output it
});
This code will traverse the DOM (admittedly probably not the most efficient thing to do) relative to the input that is currently handling the keyup event, and put values into the appropriate target inputs based on their relative locations.
DEMO

Your code is a bit obfuscated, try to format it nice next time. This will help you read it faster and will make it more maintainable.
However here is a basic example of how to achieve this:
function calculate () {
const val1 = document.getElementById('input1').value;
const val2 = document.getElementById('input2').value;
document.getElementById('output').value = Number(val1) + Number(val2);
}
$('#calculate').on('click', calculate);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="input1" type="number">
<input id="input2" type="number">
<br>
<br>
<button id="calculate">calculate</button>
<br>
<br>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
Output <input id="output" type="number">

Once you sort out the click handler, the only real issue you have is the use of relative positioning instead of ids to locate items within the row in question. Here's your code reformatted with comments explaining the changes
$(document).on('click', '.add', function(){
var html = '';
html += '<tr>';
html += '<td><select name="product_name[]" class="pu-input product_name">
<option value="">--Select--</option><?php echo
fill_unit_select_box($connect); ?></select></td>';
html += '<td><input type="text" name="mt[]" class="pu-input mt"/>
</td>';
html += '<td><input type="text" name="ream[]" class="pu-input ream"></td>';
html += '<td><input type="text" name="unit_price[]" class="pu-input
unit_price"></td>';
html += '<td><input type="text" name="d_price[]" class="pu-input d_price"></td>';
html += '<td><input type="text" name="td_price[]" class="pu-input td_price"></td>';
html += '<td><input type="text" name="vat[]" class="pu-input vat">
</td>';
html += '<td><input type="text" name="t_vat[]" class="pu-input t_vat"></td>';
html += '<td><input type="text" name="total[]" class="pu-input total"></td>';
html += '<td><button type="button" name="remove" class="btn btn-danger btn-
sm remove"><i class="fas fa-minus"></i></span></button></td></tr>';
$('#item_table').append(html);
});
// end of add.click handler
// since #item_table exists but its rows might not yet, use a delegated event handler attached to #item_table
$('#item_table').on("keyup", "input", function() { // run anytime any value changes
// locate parent row relative to the input that was typed in
var row = $(this).closest('tr');
// locate mt and so on within the row by class - don't need id
var mt = Number(row.find('.mt').val());
var price = Number(row.find('.price').val());
var discount = Number(row.find('.discount').val());
var vat = Number(row.find('.vat').val());
// output, again find the fields by class
row.find('.total').val(mt * price);
row.find('.d_price').val(mt * discount);
// etc
});
});

Related

Onchange event in dynamic table html

My requirement is I have a table having 4 columns
in first cloumn can select item name, second is item rate, third is item qty last one is the total amount
I want to get the item rate automaticaly in second column while changing item in first, and want tom get the total after focus out from qty field as the multiple opf qty and rate,
i want a row adding buton to add rows and the onchange and onblur event should working on all rows,
how can i do this ?
my coode is
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<script src="https://cdn.datatables.net/1.10.15/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.10.15/js/dataTables.bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.4/css/bootstrap-datepicker.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.4/js/bootstrap-datepicker.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"/>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<table id="item_table">
<tr><th>SL No</th><th>Item Name</th><th>Rate</th><th>Qty</th><th>Total</th><th><button type="button" name="add" class="btn btn-success btn-sm add" >add</button></tr>
</table>
<script>
$(document).ready(function(){
$(document).on('click', '.add', function(){
var html = '';
html += '<tr>';
html += '<td><input type="text" name="slno[]" /></td>';
html += '<td><select name="item[]" id=item[] onchange="show_rate()"><option value="10">Item 1</option><option value="20">Item 2</option><option value="30">Item 3</option><option value="35">Item 4</option></td>';
html += '<td><input type="text" name="rate[]" id="rate[]" /></td>';
html += '<td><input type="text" name="qty[]" id="qty[]" onblur="sum_total()"/></td>';
html += '<td><input type="text" name="total[]" id="total[]" /></td>';
html += '<td><button type="button" name="remove" class="btn btn-danger btn-sm remove" >Remove</button></td></tr>';
$('#item_table').append(html);
});
$(document).on('click', '.remove', function(){
$(this).closest('tr').remove();
});
});
function show_rate(){
var a=document.getElementsByName("item[]")[0].value;
var b=document.getElementById("rate[]");
b.value=a;
}
function capitalise(){
var c=document.getElementsByName("rate[]")[0].value;
var d=document.getElementsByName("qty[]")[0].value;
var e=document.getElementById("total[]");
e.value=+c * +d;
}
</script>
You must make your select with values in the option tags. Each option must have a unique ID or name. You can then call upon the value attribute of the option and display it in column 2. Then use simple math operators to take the value and multiply it by a set variable, which you can also get from a select by using the mentioned above method. Example 12
Look at other posts for questions about adding rows, there are tons of posts out there on that topic with exactly the code you need.

Get Values of multiple input fields from within parent element AngularJS

Firstly apologies if this has been asked before, but I have the following HTML which is generated dynamically by an angular directive (I.E When the user clicks a button, a new element is added to the page), all these entries are within a container div.
<div class="entry"><tr><td><input type="text" name="firstname"/></td>' +
'<td><input type="text" name="surname" /></td></tr></div>
Once the user submits, I want to be able to get the data from both the inputs within each entry.
Does anybody have any suggestions on how to do this?
Thank You!
It is suggested that you use ng-model and ng-submit in the directive.
<script>
angular.module('MyApp', []).directive('myDirective', function () {
return {
template: '<form ng-submit="submit()">' +
'<div class="entry">' +
'<tr>' +
'<td><input type="text" ng-model="firstname" /></td>' +
'<td><input type="text" ng-model="surname" /></td>' +
'<td><input type="submit" value="Submit" /></td>' +
'</tr>' +
'</div>' +
'</form>',
link: function (scope, element) {
scope.submit = function() {
console.log("scope.firstname", scope.firstname);
console.log("scope.surname", scope.surname);
};
}
};
});
</script>
<div ng-app="MyApp">
<div my-directive></div>
</div>
Then, you can do anything else in the submit function with firstname and surname.

How to traverse dom tree from a list of elements

I have HTML snippet which looks like this. I generate this snippet multiple times form the backend. When I click the Save button, I catch which Save button was clicked using $(this) selector. Now I want to grab the attribute item-id of the corresponding Save button. I have the following jquery code snippet. But it does not work. I have tried to look but I don't know where the error is.
<td><input type="text" size="10" value="val1" item-id="id1"></td>
<td><input type="text" value="val2" size="4"></td>
<td>
<button class="btn btn-primary save-btn">Save</i></button>
</td>
Here is the jquery snippet
$(".save-btn").click(function(){
var ems = $(this).parent().siblings();
var item_id = ems[0].child().attr("item-id");
}
click doesn't work on dynamically added elements.You need to use on('click'). Also there is no method .child() so you need to use .children().first().
This is the corrected code:
$(document).on('click', '.save-btn', function(){
var ems = $(this).parent().siblings();
var item_id = ems.children().first().attr("item-id");
});
// The text
var text="";
text += "<td><input type=\"text\" size=\"10\" value=\"val1\" item-id=\"id1\"><\/td>";
text += "<td><input type=\"text\" value=\"val2\" size=\"4\"><\/td> ";
text += "<td>";
text += " <button class=\"btn btn-primary save-btn\">Save<\/i><\/button>";
text += "<\/td>";
// Adding the text to html
$('body').html(text);
$(document).on('click', '.save-btn', function(){
var ems = $(this).parent().siblings();
console.log(ems);
var item_id = ems.children().first().attr("item-id");
alert(item_id);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
better replace item-id="id1" to data attribute html5 data-id="id1" then replace code attr('item-id') to data('id')...
$(document).on('click','.save-btn', function(){
var ems = $(this).parent().siblings(),
item_id = ems.eq(0).children('input').attr("item-id");
alert(item_id);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td><input type="text" size="10" value="val1" item-id="id1"></td>
<td><input type="text" value="val2" size="4"></td>
<td>
<button class="btn btn-primary save-btn"><i>Save</i></button>
</td>
</tr>
</table>

Not able to propagate event listener (submit for form) for element generated by(later) javascript

I have html code like -
<div class = "setup_eda_class" id = "Setup_eda">
<p>
<a> <span id="calendar_eda_form_top_x"> x </span> </a>
<br> </br>
<div id="insert_calendar_eda_form"> </div>
</p>
</div>
The div 'insert_calendar_eda_form' is inserted initially.
Javascript code
calendar_eda_add_form = function (clicked_id, arraylength){
htmlstr = "";
htmlstr += '<a> Add Events for - </a>' ;
htmlstr += '<form id="calendar_eda_add_form" action="/setupaddcalendarevent" method="POST">'
htmlstr += '<label for="start_date">Start Date</label>'
htmlstr += '<input type="text" name="start_date" />'
htmlstr += '<label for="end_date">End Date</label>'
htmlstr += '<input type="text" name="end_date" />'
htmlstr += '<br> </br>'
htmlstr += '<input type="submit" value="Add Event" />'
htmlstr += '</form>'
$("#insert_calendar_eda_form").html(htmlstr);
The form 'calendar_eda_add_form' html is created dynamically by Javascript.
HTML code for event listener
<script type="text/javascript">
$(document).ready(function(){
$('#insert_calendar_eda_form').on('submit', 'calendar_eda_add_form', function(event){
alert ('clicked add event');
event.preventDefault();
somefunction();
});
});
Calendar_eda_add_form is generated dynamically by JS. I am trying to propagate the "submit" event, but does not seem to work. Can you please help?
Missing the hash tag on the selector inside the .on()
$(document).ready(function(){
$('#insert_calendar_eda_form').on('submit', '#calendar_eda_add_form', function(event){
alert ('clicked add event');
event.preventDefault();
somefunction();
});
});
Here's a fiddle showing it working http://jsfiddle.net/ja3kaa4b/ - are you seeing any console errors in the browser?
You may be experiencing the effects of duplicate IDs. In the function calendar_eda_add_form change the ID of the form to a class and use the following code instead:
$(document).ready(function(){
$('#insert_calendar_eda_form').on('submit', '.calendar_eda_add_form', function(event){
alert ('clicked add event');
event.preventDefault();
somefunction();
});
});
UPDATE
Per the comments under the question, the above is unlikely as the form is added to the DOM only once. However, the HTML being used is not valid:
<div class = "setup_eda_class" id = "Setup_eda">
<p>
<a> <span id="calendar_eda_form_top_x"> x </span> </a>
<br> </br>
<div id="insert_calendar_eda_form"> </div>
</p>
</div>
Per the HTML spec P elements can only contain inline elements; div - the target div - is not an inline element.
Why <p> tag can't contain <div> tag inside it?
http://www.w3.org/TR/html4/sgml/dtd.html
If I understand your question, this should work:
calendar_eda_add_form = function (clicked_id, arraylength){
htmlstr = "";
htmlstr += '<a> Add Events for - </a>' ;
htmlstr += '<form id="calendar_eda_add_form" action="/setupaddcalendarevent" method="POST">'
htmlstr += '<label for="start_date">Start Date</label>'
htmlstr += '<input type="text" name="start_date" />'
htmlstr += '<label for="end_date">End Date</label>'
htmlstr += '<input type="text" name="end_date" />'
htmlstr += '<br> </br>'
htmlstr += '<input type="submit" value="Add Event" />'
htmlstr += '</form>'
return htmlstr;
// in your code I dont see where you ever do anything with `htmlstr `.
// Since you made `calendar_eda_add_form` a function, I'm assuming you meant to return `htmlstr`
// and insert the created html into your `insert_calendar_eda_form` div
// im assuming you have a reason for `clicked_id, arraylength` here but not sure what they are for
}
$(document).ready(function(){
//change this line to add the `#` and bind to `document`
$(document).on('submit','#calendar_eda_add_form',function(event){
event.preventDefault();
somefunction();
});
//put here to simulate adding form later
$('#create').click(function(){
//insert the created html into your `insert_calendar_eda_form` div
$('#insert_calendar_eda_form').html(calendar_eda_add_form);
});
});
function somefunction(){
alert ('clicked add event');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="button" id="create" value="create form"/>
<div class = "setup_eda_class" id = "Setup_eda">
<p>
<a> <span id="calendar_eda_form_top_x"> x </span> </a>
<br> </br>
<div id="insert_calendar_eda_form"> </div>
</p>
</div>

replace a <p> element with an input element

I have a p element which I want to replace with an input element when user clicks on it. The might not be present during page load so I use delegate to catch the click event.
html(after <p> was loaded)
<div class="phrases">
<div class="predefined-phrase>
<p id="1">A predefined phrase"</p>
</div>
</div>
I want it to be like this
<div class="phrases">
<div class="predefined-phrase">
<input type="text" id="1" class="form-control input-sm" value="A predefined phrase">
</div>
</div>
My js file has the following code:
$(".phrases").on('click', ".predefined-phrase", function (event){
event.preventDefault();
var phrase = $(this).children().text();
var id = $(this).children().attr('id');
var input = '<input type="text" class="form-control input-sm" id="'+id+'" value="'+phrase+'">';
$(this).children().remove();
$(this).append(input);
});
<p> is replaced normally by input but i cannot type anything. I can only type if left click is pressed on input box continiously. I also want to catch a keypress event on the new input so to edit or to delete the specific phrase. But I cannot even type on the input box. Why is this happening? Can i normally catch the keypress event after I have appended the input (and works as it should) inside the click event callback? The point is that after user presses the phrase is edited with ajax and the input box dissappears and p is loaded back with the new edited phrase or fully deleted.
$(function(){
$('.predefined-phrase p').click(function() {
var id = $(this).attr('id');
var phrase = $(this).text();
var newInput="<input type='text' id='"+id+"' value='"+phrase+"' />";
$(this).replaceWith(newInput);
});
});
DEMO FIDDLE
Just check the target. If it is a input, do nothing :
$(".phrases").on('click', ".predefined-phrase", function (event){
if($(event.target).is('input')) return;
event.preventDefault();
var phrase = $(this).children().text();
var id = $(this).children().attr('id');
var input = '<input type="text" class="form-control input-sm" id="'+id+'" value="'+phrase+'">';
$(this).children().remove();
$(this).append(input);
});
Well, this is a native JS solution, but hopefully it will point you in the right direction, or if you an use it instead of jQuery, that works too. Not that I've changed your ID to not start with a number, as mentioned by C-link, as that is not allowed.
document.getElementById("n1").addEventListener("click", function filler(){
this.outerHTML = '<input type="text" id="' + this.id + '" class="form-control input-sm" value="' + this.innerHTML + '" />
this.removeEventListener("click" filler)'
});
I would suggest the next changes:
<div class="predefined-phrase">
<input type="text" data-id="1" class="form-control input-sm" value="A predefined phrase">
</div>
jQuery script:
$('.predefined-phrase').click(function() {
var id = $('p', this).attr('data-id');
var value = $('p', this).text();
$('p', this).replaceWith('<input type="text" data-id="' + id + '" class="form-control input-sm" value="' + value + '" />')
});
First of all, don't use id starting from number.
And for your solution you can use replaceWith method like below:
$('#your_id').replaceWith('<input type="text" id="your_id" class="form-control input-sm" value="A predefined phrase" />');

Categories