2

I am creating an html form that will take quantity values in input for items and calculate the individual total cost and show it adjacent to each input box and show the grand total at the bottom of the form. I am doing it with JS and KeyUp function and trying to iterate the function.

My HTML

<p><span>T-Shirts </span> <input type="number" name ="tshirts" value="0" id="tshirts">&nbsp;&nbsp;<span class="tshirtscost">0</span><br></p>
<p><span>Shirts </span> <input type="number" name ="shirts" value="0" id="shirts">&nbsp;&nbsp;<span class="shirtscost">0</span><br></p>
<p><span>Kurtas </span> <input type="number" name ="kurtas" value="0" id="kurtas">&nbsp;&nbsp;<span class="kurtascost">0</span><br></p>

<div id="totalcost"></div>

My JS

var item = ["T-Shirt/s","Shirt/s","Kurta/s"];
var itemcost=100;
var text = "";
var i;

for (i = 0; i < item.length; i++) {
 text = item[i].replace(/ |-|&|\//g, '').toLowerCase();

 itemid="#" + text;
 itemclass="." + text + "cost";

 $(itemid).keyup(function(){
    var x = $(itemid).val();
    $(itemclass).css("background-color", "pink").html("Rs."+ (x * itemcost));
    totalcost();

});

function totalcost(){
var tot=$('#tshirts').val()*itemcost + $('#shirts').val()*itemcost + $('#kurtas').val();
    $("#totalcost").css("background-color", "pink").html("<span style='font-weight:700'>Total Cost : </span>Rs."+tot);
  }
}

The idea to iterate the js operation is because I have lot many more items for input and calculation in the form.

However, I am not sure trying to create a variable with a class name and using it in the function is a possibility. But if something similar can be done, it will save me writing lots of lines of code for each item.

This code is not working. Probably for obvious reasons that I cant see. Any help will be greatly appreciated.

user3526204
  • 509
  • 5
  • 22

2 Answers2

1

You need to use inner function because of this.

In you example, you're updating two variables in the loop - itemid and itemclass. But every function you're registering in .keyup will remember not the values for these variables, but the variable itself. And since after the last loop these variables will contain the last value, all callbacks will use the last value of itemid and itemclass. That's why you need to use inner function, so inner function will have id and cls variables created each time with the correct value. What are're looking is probably this:

$(itemid).keyup((function (id, cls) {
    return function () {
        var x = $(id).val();
        $(cls).css("background-color", "pink").html("Rs." + (x * itemcost));
        totalcost();
    }
}(itemid, itemclass)));

I've created a plunker to show that.

Community
  • 1
  • 1
Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
  • @user3526204, it's working fine for me, please see [this plunker](https://plnkr.co/edit/REcVxpuZ1I5s4ltbEErV?p=preview). – Max Koretskyi Nov 27 '16 at 14:59
  • is this line making it work... ? Let me check... – user3526204 Nov 28 '16 at 04:11
  • Yes ! it is ! Only thing is the final total is showing multiplied by 10...let try to fix that.... Thanks a ton ! Choosing this as the answer. – user3526204 Nov 28 '16 at 04:14
  • Just one query....why is itemid working in the line $(itemid).keyup((function (id, cls) { ...... but not in........ $(itemid).keyup(function(){ var x = $(itemid).val(); ? – user3526204 Nov 28 '16 at 04:20
  • I got it, I have to use var x = $(this).val(); ...still figuring out why $(itemclass).css("background-color", "pink").html("Rs."+ (x * itemcost)); won't work... .. – user3526204 Nov 28 '16 at 04:32
  • Got that too...had a stray apostrophe in the definition of the variable...thanks all guys.. – user3526204 Nov 28 '16 at 04:34
  • Only thing is, the itemclass is picking up the last class name in the loop instead of the current class name ..in my version. And the totalcost() is showing the figure multiplied 10 times in both the versions (mine and the accepted answer) ! – user3526204 Nov 28 '16 at 04:55
  • @user3526204, yes, [read here](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) about why this happens. That's why I used [IIFE](http://stackoverflow.com/questions/8228281/what-is-the-function-construct-in-javascript) to wrap correct `itemid` and `itemclass` and access them inside the function as `id` and `cls` – Max Koretskyi Nov 28 '16 at 07:13
  • Ok. Thanks a lot. Got it. but just out of curiosity, was wondering what exactly was wrong with $(itemid).keyup(function(){ var x = $(itemid).val(); var x = $(itemid).val(); } why that will not work ? Though the itemid variable has the id name in it. Is there some way that could work as well ? – user3526204 Nov 28 '16 at 10:56
  • Reason I am asking is, I am trying to get the totalcost() also to iterate through the item values and calculate the grand total without having to add each input value with id name. I have about 50 items and these may change later. – user3526204 Nov 28 '16 at 10:58
  • @user3526204, have you read [this](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example)? – Max Koretskyi Nov 28 '16 at 11:16
  • Yes, I did but honestly couldn't really relate...my bad...not too good in js ...sorry :( It was way beyond my mental capabilty... – user3526204 Nov 28 '16 at 12:10
  • @user3526204, I added some details to the answer. Please check. – Max Koretskyi Nov 28 '16 at 12:18
  • Got it ! Thanks a ton. I am now working on trying to make the totalcost() work with looping too.... :) – user3526204 Nov 28 '16 at 12:27
1

You may register an event to all the input elements without iterating through each one of them manually.

jQuery('p > input').keyup(function() {
  // handle keyup event
});

This piece of code assigns an enclosure to be executed on keyUp to all p > input elements in the page. I would personally recommend enclosing the items I am addressing inside a container, to prevent targeting others you did not originally intended.


To access the adjacent span's, you may use many different methods, this uses .next(), for example:

jQuery('p > input').keyup(function(e) {
  // handle keyup event
  jQuery(e.target).next().css('color', 'fuchsia');
});
Johnny Bueti
  • 637
  • 1
  • 8
  • 27