Undefined error getting parents childs input value - javascript

I have a table that looks like this:
<table>
<tr>
<td class="packing-vol">0.19</td>
<td class="qty-cell"><input type="text" name="qty[]" class="qty" value="2" /></td>
</tr>
<tr>
<td class="packing_total">0.70</td>
<td class="qty-cell"><input type="text" name="qty[]" class="qty" value="1" /></td>
</tr>
</table>
I'm looping through each occurence of .packing-vol getting it's text, then I want to get the qty from the same row so I go up to it's parent then drill into the .qty class. But when I alert(qty) i get 'undefined' message.
var total = 0;
jQuery('.packing-vol').each(function(i) {
var qty = jQuery(this).parent("td.qty-cell .qty").val();
alert(qty);
var cur = parseFloat(jQuery(this).text());
if(!isNaN(cur)){
total = total + cur;
}
});

I think you should do this:
var qty = jQuery(this).parent().find("td.qty-cell .qty").val();
You need to go 1 level up (using .parent) and then find your field inside with .find

parent is just one level upwards. You can't use it to go inside trees again.
parents is multiple levels upwards. You can't use it to go inside trees again.
You can use parent/parents and then use find to do what you want, or even better:
var total = 0;
jQuery('.packing-vol').each(function(i) {
var qty = jQuery(this).parent().children('.qty-cell').children('.qty').val();
alert(qty);
var cur = parseFloat(jQuery(this).text());
if (!isNaN(cur)){
total = total + cur;
}
});
You could also use find, but it is slower than going directly inside, because it has to search the DOM object.
But you could also do:
var qty = jQuery(this).parent().find("td.qty-cell .qty").val();

Instead of
var qty = jQuery(this).parent("td.qty-cell .qty").val();
Try:
var qty = jQuery(this).parent().find(".qty").val();

Related

jQuery Math Operation on Multiple Elements

I have a simple invoicing page so I can invoice my client, however when I am going to perform multiplication to the quantity and price, the row total is not adding. Here's my jQuery so far.
$(":input").bind('keypress keydown keyup change', function(){
var price = parseFloat($(this).closest('.tr').find('.price').val(),10),
var qty = parseFloat($(this).closest('tr').find('.quantity').val(),10);
var v = '';
if(!isNaN(price) && !isNaN(qty)) {
v = price * qty;
}
$(this).closest('tr').find('.rowtotal').val(v.toString());
});
And this is my HTML:
<table>
<tr>
<td>1</td>
<td><input name="item_name[]"class="form-control"></td>
<td><input name="item_description[]"class="form-control"></td>
<td><input name="item_price[]"class="form-control price"></td>
<td><input name="item_quantity[]"class="form-control quantity"></td>
<td><span class="rowtotal">0.00</span></td>
</tr>
<tr>
<td>2</td>
<td><input name="item_name[]"class="form-control"></td>
<td><input name="item_description[]"class="form-control"></td>
<td><input name="item_price[]"class="form-control price"></td>
<td><input name="item_quantity[]"class="form-control quantity"></td>
<td><span class="rowtotal">0.00</span></td>
</tr>
</table>
Now on my page, it shows no error while reviewing the console, but it does not perform the operation that I have created following this post "Automatically updating input field with math using jquery?"
Any help is appreciated.
TIA
You've got a typo in this line:
var price = parseFloat($(this).closest('.tr').find('.price').val(),10),
^^ Shouldn't be a class selector
Should be:
var price = parseFloat($(this).closest('tr').find('.price').val(),10),
Next line is fine. Additionally, you can replace all those events with:
$(":input").on("input", function() {
// Triggers on any input event
});
You also have a few other issues:
There is no overload for parseFloat which takes two parameters
You are using .val() to set the text of the span. You need to use .text() instead
You should probably cache the <tr> selector. You don't need to go find it each time.
$(":input").on('input', function(){
var $tr = $(this).closest("tr");
var price = parseFloat($tr.find('.price').val()),
qty = parseFloat($tr.find('.quantity').val());
var v = '';
if(!isNaN(price) && !isNaN(qty)) {
v = price * qty;
}
$tr.find('.rowtotal').text(v.toString());
});
Working Example

Can't get the value of closest prev td input

I need your help!
I have fiddle and what I want is multiplicate two td's values and the result go to the next td.
$(document).ready(function(){
$( "input[id^='unitval']" ).keyup(function() {
var input_value = parseFloat($(this).val());
var Cant = $("#item_Cant").text();
var totval = (input_value * Cant);
if (!isNaN(input_value)) { // the input is a number
//$("#totval1").val(totval); // update second field
$(this).closest('td').next().find('input').val(totval);
} else { // the input wasn't a number
$("#totval1").val("not a number?"); // show an error mesage
}
});
});
But just works with the first row because the second one still multiplicating with the td of first row not the actual td
I tried to change the:
var Cant = $("#item_Cant").text();
with
var Cant = $("input[id^='item_Cant']").text();
But don't works, I have not idea why, even first row.
But in this line I need the correct Jquery for get the last td input value in the same tr.
I tried many lines but without success, hope you can understand me.
Thanks for your help.
You are always referring to item_Cant ID every time you do your calculation. You need to find the quantity element with respect to your current input field.
Here's one approach that'll work with your current structure:
$(document).ready(function () {
$("input[id^='unitval']").keyup(function () {
var input_value = parseFloat($(this).val());
var Cant = $(this).closest('tr').find('[id^="item_Cant"]').text();
var totval = (input_value * Cant);
if (!isNaN(input_value)) { // the input is a number
//$("#totval1").val(totval); // update second field
$(this).closest('td').next().find('input').val(totval);
} else { // the input wasn't a number
$("#totval1").val("not a number?"); // show an error mesage
}
});
});
Here's a fiddle: http://fiddle.jshell.net/P89Tj/1/
You cannot have multiple identical ids on a page.
Use classes instead:
$(document).ready(function(){
$( "input.unitval" ).keyup(function() {
var input_value = parseFloat($(this).val());
var Cant = $(this).parent().prev().text();
var totval = (input_value * Cant);
if (!isNaN(input_value)) { // the input is a number
//$("#totval1").val(totval); // update second field
$(this).parent().parent().find('.totval').val(totval);
} else { // the input wasn't a number
$("#totval1").val("not a number?"); // show an error mesage
}
});
});
<table width="500" border="1">
<tr>
<td>Quantity</td>
<td>VAL1</td>
<td>RESULT Quantity*VAL1</td>
<td>VAL2</td>
<td>RESULT Quantity*VAL2</td>
</tr>
<tr>
<td>5</td>
<td><input class="unitval" type="text"/></td>
<td><input readonly class="totval" type="text"/></td>
<td><input class="unitval" type="text"/></td>
<td><input readonly class="totval" type="text"/></td>
</tr>
<tr>
<td>4</td>
<td><input class="unitval" type="text"/></td>
<td><input readonly class="totval" type="text"/></td>
<td><input class="unitval" type="text"/></td>
<td><input readonly class="totval" type="text"/></td>
</tr>
</table>
http://fiddle.jshell.net/8CGXf/

Add dynamic href to table with jquery

I have a table with a template to insert rows, I would like to make those rows clickable so that I can edit them. How do I append an href value to the template?
My Template
<tr class="template" style="display:none;">
<td><span class="item_num"> Num </span></td>
<td><span class="item_desc"> Description </span></td>
<td><span class="item_price"> Price </span></td>
<td><span class="item_ref">ref</span></td>
</tr>
My Javascript
var newRow = $('#quote .template').clone().removeClass('template');
var quoteItem = {
number: 1,
description: myDescriptionVariable,
price: myPriceVariable,
};
template(newRow, quoteItem)
.insertAfter('#quote tr.template')
.fadeIn()
function template(row, quoteItem) {
row.find('.item_num').text(quoteItem.number);
row.find('.item_desc').text(quoteItem.description);
row.find('.item_price').text(quoteItem.price);
row.find('.item_ref').attr('href','hello');
return row;
}
You can use .data()
row.find('.item_ref').data('ref','hello');
with
<span class="item_ref" data-ref="" > Edit</span>
Then you can use it like --
console.log($('.item-ref').data('ref'));
If you just wish to store data somehow then this might be useful. Let me know if there's something more you want to do. Or what kind of data href holds and how you want to use it further.
UPDATE
From what I understand up till now is, you want to add rows dynamically that needs to editable after insertion. Each row contain some fields with certain values. And you want to save ref in item_ref class.
So here's how you can do it -
var num = 1;
var myDescriptionVariable = 111;
var myPriceVariable = 999;
// You may have some other element triggers cloning
$("button").click(function(){
var newRow = $('#quote .template').clone().removeClass('template');
var quoteItem = {
number: num,
description: 'Description ' + myDescriptionVariable, // added to distinguish items
price: myPriceVariable + ' USD', // added to distinguish items
linkToPopup: myDescriptionVariable + '_link_goes_here' // added to distinguish items
};
template(newRow, quoteItem)
.insertAfter('#quote tr.template')
.show();
});
function template(row, quoteItem) {
row.find('.item_num').text(quoteItem.number);
row.find('.item_desc').text(quoteItem.description);
row.find('.item_price').text(quoteItem.price);
// here 'href' will hold desired link_to_popup
row.find('.item_ref').data('href',quoteItem.linkToPopup);
myDescriptionVariable+= 1; // added to distinguish items
myPriceVariable+=2; // added to distinguish items
num+=1; // added to distinguish items
return row;
}
$("#quote").on("click", ".item_ref",function(){
// this will give to desired link_to_pop_val
alert($(this).data('href'));
});
I've added a button to give demonstration. This approach definitely avoid unnecessary DOM elements like hidden inputs to be added for each row. With .data() you same multiple kind of information for every field like -
$("span").data('key_1', value_1);
$("span").data('key_2', value_2);
$("span").data('key_2', value_3);
fiddle for demonstration
I think that's what you want to do and should serve the purpose. :)
There are actually a few ways to do this, one of them being:
Add some inputs to your template that are hidden
Bind a click event to the row that will hide the spans and show the input
You would of course need a save button and do something with the values, but I didn't do that part.
A condensed not fully working demo: http://plnkr.co/edit/GGM0d9wfNcoZBd5kKCwA
<tr class="template" style="display:none;">
<td><span class="item_num"> Num </span><input type="text" style="display:none" /></td>
<td><span class="item_desc"> Description </span> <input type="text" style="display:none" /></td>
<td><span class="item_price"> Price </span><input type="text" style='display:none' /></td>
<td><span class="item_ref">ref</span><input type="text" style='display:none' /></td>
</tr>
jquery:
$(document).on('click', '#quote tr', function(e) {
$('span', this).hide();
$('input', this).show();
});
$('#add').on('click', function(e) {
var newRow = $('#quote .template').clone().removeClass('template');
var quoteItem = {
number: 1,
description: 'myDescriptionVariable',
price: 100,
};
template(newRow, quoteItem)
.insertAfter('#quote tr.template')
.fadeIn()
});
function template(row, quoteItem) {
row.find('.item_num').text(quoteItem.number).next().val(quoteItem.number);
row.find('.item_desc').text(quoteItem.description).next().val(quoteItem.description);
row.find('.item_price').text(quoteItem.price).next().val(quoteItem.price);
row.find('.item_ref').attr('href','hello').next().val('hello');
return row;
}

jquery calculate BMI

I stuck to this problem. I want to calculate body BMI.
My HTML - every row <tr> is created dynamically by PHP.
<tbody>
<tr id="person_bmi">
<td>Jack</td>
<td><input name="weight" type="text" class="span1" id="weight" maxlength="5"></td>
<td><input name="height" type="text" class="span1" id="height" maxlength="5"></td>
<td><input name="bmi" type="text" class="span1" id="bmi" readonly></td>
</tr>
<tr id="person_bmi">
<td>Michael</td>
<td><input name="weight" type="text" class="span1" id="weight" maxlength="5"></td>
<td><input name="height" type="text" class="span1" id="height" maxlength="5"></td>
<td><input name="bmi" type="text" class="span1" id="bmi" readonly></td>
</tr>
//and so on...
</tbody>
What I try to achieve is every person Jack, Michael, so on.. will have their own BMI values in #bmi textfield after calculated their own $weight/($height*100/$height*100) value. I try to create my own code but its not make sense..
$("#weight, #height").keyup(function(){
var $weight= $("#weight").val();
var $height= $("#height").val();
var $bmi = $weight/($height/100*$height/100);
$("#bmi").val(parseInt($bmi));
});
Can someone show me the way? Thanks
Remove the duplicate IDs and use class="weight", class="height" and class="bmi" instead. Then you can use the following jQuery code:
$(".weight, .height").keyup(function() {
var row = $(this).closest('tr');
var weight = parseInt(row.find('.weight').val(), 10);
var height = parseInt(row.find('.height').val(), 10);
var bmi = weight / (height / 100 * height / 100);
row.find('.bmi').val(isNaN(bmi) ? '' : bmi);
});
If you want to allow floats for the input values, replace the two lines containing parseInt with these:
var weight = parseFloat(row.find('.weight').val());
var height = parseFloat(row.find('.height').val());
Demo: http://jsfiddle.net/KStjd/
The problem is most likely that val returns strings and strings can't me multiplied or divided. As mentioned by ThiefMaster you also can't have multiple items with the same id so change <tr id="person_bmi"> to <tr class="person_bmi">
$(".person_bmi input").keyup(function() {
var $parent = $(this).parent().parent();
var weight = parseFloat($parent.find("[name='weight']").val());
var height = parseFloat($parent.find("[name='height']").val());
var bmi = weight/(height/100*height/100);
$parent.find("[name='bmi']").val(bmi);
});​
Here is a fiddle of a full working example:
http://jsfiddle.net/uCAYF/1/
The .find function you see being used is "scoped" in the sense that it will only find nodes that are descended from the element it was called on. Since it is scoped it will safely select the the input field of interest on the given row.
jQuery lets you use CSS selectors when searching for elements so you can do more than just look things up by id. For instance, in the example above I find your input elements by their name.
Here are some good resources on the different selectors you can use and how they work:
http://www.w3.org/TR/CSS2/selector.html
http://www.w3.org/TR/selectors/
Please try to add unique id's:
var weight= parseFloat($("#person1_weight").val());
var height= parseFloat($("#person1_height").val());
var bmi = weight/(height/100*height/100);
$("#person1_bmi").val(bmi); // bmi is not an integer
Or the following will probably work regardless of the invalid non unique id's so you could leave them (not recommended) or take all of the id's off. It uses the input positions.
$("tr input:eq(0), tr input:eq(1)").keyup(function(){
var weight= parseFloat($(this).closest('tr').find('input:eq(0)'));
var height= parseFloat($(this).closest('tr').find('input:eq(1)'));
var bmi = weight/(height/100*$height/100);
$(this).closest('tr').find('input:eq(2)').val(bmi);
});
$("input[name=weight], input[name=height").keyup(function() {
var row = $(this).parent().parent(),
weight = parseFloat($('input[name=weight]', row).val()),
height = parseFloat($('input[name=height]', row).val());
var bmi = weight / (height / 100 * height / 100);
$('.bmi', row).val(isNaN(bmi) ? '' : bmi);
});
Working Sample
$(document).ready(function()
{
$("PutYourButtonID_Here").click(function(event){
var weight= parseFloat($("#person1_weight").val());
var height= parseFloat($("#person1_height").val());
var bmi = weight/(height/100*height/100);
$("#person1_bmi").val(bmi);
});
});

Using jquery to get per row totals and grand total of table

So the short version of this is: Can I traverse only the elements within the matched element of the selectors before the each()? Or is there a simpler way of getting what I want without an each() loop?
I thought this would be much easier, which makes me think I'm just missing some fundamental principle of element traversing with jquery.
So here's the scenario:
I have a table (and it is appropriate in this case), where each cell has a text input. The last input is read-only and is supposed to be the total sum of the other values entered on that row. I have a really messy js script for finding both the totals of each row and then the grand total of each row total.
Here's the basic HTML:
<table>
<thead>
<tr><th>Col 1</th><th>Col 2</th><th>Col 3</th><th>Total</th></tr>
</thead>
<tbody>
<tr id="row1"><td><input type="text" /></td><td><input type="text" /></td><td><input type="text" /></td><td class="total"><input type="text" readonly="readonly" /></td></tr>
<tr id="row2"><td><input type="text" /></td><td><input type="text" /></td><td><input type="text" /></td><td class="total"><input type="text" readonly="readonly" /></td></tr>
<tr id="row3"><td><input type="text" /></td><td><input type="text" /></td><td><input type="text" /></td><td class="total"><input type="text" readonly="readonly" /></td></tr>
</tbody>
</table>
The javascript will validate that the data entered is numerical, just to be clear.
So I have a event listener for each input for onchange that updates the total when the user enters data and moves to the next cell/input. Then I have a function called updateTotal that currently uses for loops to loop through each row and within that loop, each cell, and finally sets the input in the total cell to sum.
Quick note: I have included the code below to show that I'm not just looking for a hand out and to demonstrate the basic logic of what I have in mind. Please feel free to skim or skip this part. It works and doesn't need any debugging or critique.
This is what that looks like:
function updateTotal() {
table = document.getElementsByTagName("tbody")[0];
allrows = table.getElementsByTagName("tr");
grandtotal = document.getElementById("grand");
grandtotal.value = "";
for (i = 0; i < allrows.length; i++) {
row_cells = allrows[i].getElementsByTagName("input");
row_total = allrows[i].getElementsByTagName("input")[allrows.length - 2];
row_total.value = "";
for (ii = 0; ii < row_cells.length - 1; ii++) {
row_total.value = Number(row_total.value) + Number(row_cells[i][ii].value);
grandtotal.value = Number(grandtotal.value) + Number(row_cells[i][ii].value);
}
}
}
Now I am trying to re-write the above with jquery syntax, but I'm getting stuck. I thought the best way to go would be to use each() loops along the lines of:
function findTotals() {
$("tbody tr").each(function() {
row_total = 0;
$($(this) + " td:not(.total) input:text").each(function() {
row_total += Number($(this).val());
});
$($(this) + " .total :input:text").val(row_total);
});
}
But using $(this) doesn't seem to work in the way I thought. I read up and saw that the use of $(this) in an each loop points to each matched element, which is what I expected, but I don't get how I can traverse through that element in the each() function. The above also leaves out the grand_total bit, because I was having even less luck with getting the grand total variable to work. I tried the following just to get the row_totals:
$($(this).attr("id") + " td:not(.total) input:text").each(function() {
with some success, but then managed to break it when I tried adding on to it. I wouldn't think I'd need each row to have an id to make this work, since the each part should point to the row I have in mind.
So the short version of this is: Can I use the each loop to traverse only the elements within the matches, and if so, what is the correct syntax? Or is there a simpler way of getting what I want without an each loop?
Oh, one last thought...
Is it possible to get the numerical sum (as opposed to one long string) of all matched elements with jquery? I'll research this more myself, but if anyone knows, it would make some of this much easier.
You are trying to set your context incorrectly try this:
function findTotals() {
$("tbody tr").each(function() {
row_total = 0;
$("td:not(.total) input:text",this).each(function() {
row_total += Number($(this).val());
});
$(".total :input:text",this).val(row_total);
});
}
For more information about the context check out the jquery docs: http://docs.jquery.com/Core/jQuery#expressioncontext
There can be two parameters for a selector. The second parameter is the context htat that the search is to take place in. Try something like the following:
$('#tableID tbody tr).each(function(){
//now this is a table row, so just search for all textboxes in that row, possibly with a css class called sum or by some other attribute
$('input[type=text]',this).each(function(){
//selects all textbosxes in the row. $(this).val() gets value of textbox, etc.
});
//now outside this function you would have the total
//add it to a hidden field or global variable to get row totals, etc.
});

Categories