Quick question on the .data() in jQuery: My variable "valone" reaches into a dropdown menu within some HTML for the "data-whatever" value in the dropdown and then plugs it into the jQuery equation. But it also seems to be getting the "option value" value from the dropdown and includes it into the math somehow, even though I don't specify it to do so...
var valone = $('#os0 option:selected').data('whatever');
Am I missing something in this .data() function? Or do I have something extra that is not necessary?
(I have the complete jQuery and HTML below.)
jQuery
$(document).ready(function(){
var valone = $('#os0 option:selected').data('whatever');
var valtwo = $('#os1').val();
var valthree = $('#os2').val();
var total = ((valone * 1) * (valtwo * 1) * (valthree * 1));
$('.calc').each(function(){
if($(this).val() != '')
{
total += parseInt($(this).val());
}
});
HTML
<select style="width: 190px;" class="calc"
name="os0" id="os0" type="text">
<option value="250" data-whatever="5">250
</option>
<option value="500" data-whatever="6">500 </option>
<option value="1000" data-whatever="7">1000
</option>
<option value="2000" data-whatever="8">2000
</option>
<option value="5000" data-whatever="9">5000
</option>
</select>
Any help or advice would be greatly appreciated!
.data is retrieving the correct value. The problem occurs with this piece:
$('.calc').each(function(){
if($(this).val() != '')
{
total += parseInt($(this).val());
}
});
The variable total is computed above this point is what you expect. .each is iterating over each select element again and adding the selected value to the total.
In answer to your question, you are missing nothing. Data stores one thing, the value set to it, either the hardcoded value in the element attribute, or the one set via jquery. What is the point in doing valone * 1, why not just valone? you are over complicating it. It should be
var total = valone * valtwo * valthree;
or
var total = (valone * valtwo) * valthree`; //valone will be multiplied with valtwo first before multiplying that total with valthree
Depending on what you are calculating.
Related
I'm programming an invoice program. I want to calculate prices row by row. I have a table with rows and columns. A single row consists of 6 columns: "product", "description", "unit cost", "quantity", "vat%" and "total price". VATs can be selected from 4 options in dropdown list.
How to read selected values from dropdown list row by row?
My HTML is like this:
<table id="items">
... ...
... ...
<td><form action="dropdown">
<select id="dropdown-vat">
<option value="0">0%</option>
<option value="10">10%</option>
<option value="14">14%</option>
<option value="24" selected>24%</option>
</select>
</form></td>
... ...
... ...
</table>
I did a JS function like this but it works properly only on the first line.
function update_price() {
var row = $(this).parents('.item-row');
var e = document.getElementById("dropdown-vat");
var vatUser = e.options[e.selectedIndex].value / 100 +1; // THIS IS THE PROBLEM
vatUser = roundNumber(vatUser,2);
var price = row.find('.cost').val().replace("€","") * row.find('.qty').val() * strUser;
price = roundNumber(price,2);
isNaN(price) ? row.find('.price').html("N/A") : row.find('.price').html(price+"€");
The function works properly on the first line.
The price is calculated "cost" * "qty" * "1 + selected VAT"
For example 10 * 1 * 1.20 = 12. // HERE vat is 20% so 1 + 0.2 = 1.2
The problem appears if user adds a second line.
Then the calculator uses vat from the first line.
If the first line is 10 * 1 * 1.2 = 12,
Then second line works like this: 10 * 1 * 1.0 = 12. Instead of using 0% (1.0), program uses 20% (1.2, from the first line).
EDIT:
Function update_price() is called when user changes a cost (blur), a qty(blur) or a vat(click) value.
Here's how I recently resolved a similar-ish issue - and why you are seeing what you are seeing.....
You get the number from the first line as JS (and, therefore, jQuery) can only have UNIQUE 'ids', so the second line (with the same id) is never read.
To solve it, use a 'combo' of things - namely, use a class for a common listener, then grab the info on a 'change' function.
<select id="dropdown-vat" class="vat">
<option>..... as you have them </option>
</select>
in the script....
$(".vat").change(function() {
var selected = this.selectedOptions[0]);
// now you can get its value, classes, whatever
console.log("value of selected is ", selected.val());
});
There may be more direct ways to get this, though this worked for what I needed.
The point here is that IDs must be unique, so you could also make a unique id for each line, then process the change (similar to what I have shown). If you need the id from that line:
var theIdOfTheSelectedLine = selected.id;
There is likely a lot more to totally answering the question, though this should help you with the main issue (non-unique ids on elements).
You can just use the value of the select element
var e = document.getElementById("dropdown-vat");
e.onchange = function() {
// value of e... this or event.target
console.log(this.value);
console.log(event.target.value);
}
<select id="dropdown-vat">
<option value="0">0%</option>
<option value="10">10%</option>
<option value="14">14%</option>
<option value="24" selected>24%</option>
</select>
EDIT: your question is unclear as we don't know what .item-row is and we can't see what a cost (blur), a qty(blur) is about.
My best guess is that following should work:
First change select to use class: <select class="dropdown-vat">
Then, seeing you use jQuery:
function update_price() {
var row = $(this).parents('.item-row'); // the parent table row???
var vatUser = row.find(".dropdown-vat").val();
// etc
}
For dynamically added elements you should use delegated event handlers. Assuming your table already created when running js code:
$("table#items").on("change", ".dropdown-vat", update_price);
I'd like to add a data value to an option tag in a select element. For example data-price but my problem is that I have multiple select tags. So how do I get JavaScript to grab the data value of that option that the user selects?
How I want it to work:
Select element #1 contains:
<select onchange="updatePrice()">
<option data-price="1">Apple $1</option>
<option data-price="2">Potato $2</option>
<option data-price="3">Bag of Grapes $3</option>
</select>
Select element #2 contains:
<select onchange="updatePrice()">
<option data-price="5">Really good cake</option>
<option data-price="15">Super Good Cake</option>
</select>
Then I'm honestly not sure what to do in the JS... But I want it to grab what the user selected, get the data-price then calculate the total (just by adding select1 + select2).
EDIT: My answer is different than this question because my question is more specific and requires different methods. Even though this is specific it could help a developer in the future by the answers it gets. Therefore it is not a duplicate but a more specific question than the other. Though that question has a simpler answer that could be plugged in if the developer knows how to.
Here is some code matching your discription. A few notes: Use the value attribute to get direct access to the option value from the select element. The unary operator (+) converts the two values from strings to a operatable numbers. The third div is just to show the output total value.
function updatePrice(){
var s1 = document.getElementById("option1");
var s2 = document.getElementById("option2");
var total = +s1.value + +s2.value;
document.getElementById("price").innerHTML = "Total: $" + total
// to get the text within the selected option
var h1 = s1.options[s1.selectedIndex].text;
return total;
}
<select id="option1" onchange="updatePrice()">
<option value="1">Apple $1</option>
<option value="2">Potato $2</option>
<option value="3">Bag of Grapes $3</option>
</select>
<select id="option2" onchange="updatePrice()">
<option value="5">Really good cake</option>
<option value="15">Super Good Cake</option>
</select>
<div id="price"></div>
Let me know if you need any further explanation. Cheers.
This is a bit tricky. You need to give an identifier so our code won't get confused.
<select id="goods1" onchange="updatePrice(this)">
<option data-price="0">Select one</option>
<option data-price="1">Apple $1</option>
<option data-price="2">Potato $2</option>
<option data-price="3">Bag of Grapes $3</option>
</select>
<select id="goods2" onchange="updatePrice(this)">
<option data-price="0">Select one</option>
<option data-price="5">Really good cake</option>
<option data-price="15">Super Good Cake</option>
</select>
First, add a global variable to storing current price. Second, store the identifier and the price value. Finally, manipulate the current price.
<script>
let price = 0;
let stored = {};
const updatePrice = elm => {
const id = elm.id;
const selectedPrice = parseInt(
Array.from(
elm.children
).filter(x => x.selected)[0].dataset.price
);
price = 0;
stored[id] = selectedPrice;
Object.keys(stored).forEach(key => price += stored[key]);
console.log(`Price: ${price}`);
};
</script>
Add some unique class to all selectbox whos valued need to be involved in total calculation like mul_ck
//when even a single selectbox change it will trigger re-calculation
$('.mul_ck').change(function(){
var total = 0;
//grab all _mul_ck_ and loop over them
$('.mul_ck').each(function(){
var selectValue = $(this).find(":selected").attr('data-price');
total += parseFloat(selectValue);
});
alert(total);
});
Let's say i've got 5 selects in an html form but you can only choose options from 3 of them. I need to accomplish the following: 1. calculate a total price, 2. dynamically pass set variables (that will eventually get passed to json for PHP) equal to the name attr of the selected options.
The problem i'm having is that i'm using value ="1" on every option. Then defining the price which is updated each time they select another option by statically assigning the variable with an if else. In what i'm doing each select has many options to choose from.
Where i'm stuck:
Either i'm going to use the name attribute and pass over 5 variables (using option:selected) or there is a way to accomplish this so my database only needs 3 columns to store to the database instead of 5.
I was hoping to accomplish this in the script on the page, rather than in the PHP. Can you do this dynamically and only send over 3 variables for JSON to pass off to the php or is this just going to be easier and faster to send over 5? Yes i'm very new to javascript and jquery :)
<form id = "testform" name = "testform" method="POST" action="test.php">
<select class = "choose" id="choice1">
<option value="0" selected=""></option>
<option value="1"> Choice 1.a</option>
</select>
<select class = "choose" id="choice2">
<option value="0" selected=""></option>
<option value="1"> Choice 1.b</option>
</select>
<select class = "choose" id="choice3">
<option value="0" selected=""></option>
<option value="1"> Choice 1.c</option>
</select>
<select class = "choose" id="choice4">
<option value="0" selected=""></option>
<option value="1"> Choice 1.d</option>
</select>
<select class = "choose" id="choice5">
<option value="0" selected=""></option>
<option value="1"> Choice 1.b</option>
</select>
<label><h4>Total:$</h4> <input style="" type="number" class="num" name="amount" value="0.00" readonly="readonly" /></label>
<script type="text/javascript">
$('select').change(function(){
var form = this.form;
var sum = 0;
var price;
$('select :selected').each(function() {
sum += Number($(this).val());
});
if (sum > 3) {
alert("You can only choose 3 classes");
$('select.choose').each(function() {
$('.choose').val(0);
});
}
if (sum == 1){
price = 80;
}
else if (sum == 2) {
price = 130;
}
else if (sum == 3) {
price = 180;
}
$(".num").val(price);
form.elements['total'] = price;
});
Check how many selects have a value of something other than 0, make sure it's not more than 3, then get the name of those selects
$('select').on('change', function(){
var selected = $('select').filter(function() {
return parseInt(this.value, 10) !== 0;
}),
sum = selected.length,
price = [80, 130, 180][sum - 1],
names = selected.map(function() {
return this.id; // selects don't seem to have names ?
}).get();
if (sum > 3) {
alert("You can only choose 3 classes");
} else {
$('.num').val(price);
}
console.log(names, sum)
});
FIDDLE
I have a specialized e-commerce cart I built where the customer selects how many of rooms, floors, etc. from a table and then it calculates the value live.
Html table entries for each drop down option looks like this
<table>
<td><select onchange="calculateall()" id="roomsclear1" size="1">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select> </td>
</table>
<h1> Total:<h1> <p id="total"> Final Value goes here after calculation of all 20 options</p>
Each type of cleaning service unfortunately has a different price point so I tried this switch statement.
var selectedt = document.getElementsByTagName('select');
function calculateall() {
for (var i = 0; i < selectedt.length; ++i) {
var calcit = selectedt.options[selectedt[i].selectedIndex].value;
var typeid = selectedt[i].id;
switch (typeid) {
case 'roomsclean1':
calcit = calcit * 65;
break;
}
document.getElementById("total").innerHTML = calcit;
}
}
Questions:
I'm only getting a 0 or 1 value written to total in HTML no matter what option I select from the table. I assume I'm screwing up on the Javascript.
Is a switch statement the most efficient option? 20+ options each with different pricing per # of rooms selected
I put an example of the cart on a temporary page here(slow!):
52.11.14.57:9000/#
JSfiddle: https://jsfiddle.net/mvc1poad/
The ID in the example correspondes to carpet cleaning tabs: rooms(clean)
Edit: Rakesh_Kumar is correct, the issue is the lack of parseInt. Adding that should address the issue when calculating values.
You mentioned you can output the actual values (which I'd recommend since it will simplify your script slightly). Personally, I would wrap an element around your select element(s) and allow a change event to bubble up (rather than an inline event handler like calculateall - just cleans up your HTML).
Something like:
<form id="ourForm">
<select id="cleaning">
<option value="0">Select cleaning</option>
<option value="0">No cleaning</option>
<option value="10">Cleaning final day only</option>
<option value="50">Cleaning 5 days</option>
</select>
<!-- additional elements here -->
</form>
And a simple JS event listener like this:
document.forms[0].addEventListener('change', function(e) {
var i = 0,
query = this.querySelectorAll('select'),
len = query.length,
total = 0;
for(; i < len; i++) {
if (parseInt(query[i].value, 10) > 0) {
total += parseInt(query[i].options[query[i].selectedIndex].value, 10);
}
}
// Do something with total here
}, true);
Here's a demo fiddle: http://jsfiddle.net/sj9o6Lnb/
If you're interested in using a multiplier, you could create a map which you then multiply the values by. Something like:
var price_map {
rooms_clean: 65,
breakfast: 100
}
Which you then reference the price by an id (or some other attribute)
for(; i < len; i++) {
total += price_map[query[i].id] * parseInt(query[i].options[query[i].selectedIndex].value, 10);
}
http://jsfiddle.net/sj9o6Lnb/1/
Here's an updated fiddle based on your site (with the four options and clean/protect): http://jsfiddle.net/sj9o6Lnb/2/
And an edited fiddle that you created: https://jsfiddle.net/mvc1poad/1/ (this one here just calculates based on a data attribute, which you would need to add)
You have made a silly mistake, because of which you are not getting expected output.
Instead of doing like:
//selectedt is HTMLCollection having list of all elements with tag "select"
//& typeof calcit is String, which you need to make a number before multiplying with 65
var calcit = selectedt.options[selectedt[i].selectedIndex].value;
do,
var calcit = parseInt(selectedt[i].options[selectedt[i].selectedIndex].value);
And, apart from switch usage, what other approach you are thinking to take. For Obvious reasons, switch is more preferable than if-else.
I have set up a function to take care of my metric conversion an it's not so seamless. I would like to convert lbs to kg and kg to lbs. The problem that i am having is using the jquery change function. It's causing the conversion to only happen on a change but sometimes i just want to due back to back conversions from lbs to kg and it gets stuck and convert the lbs to more lbs or kg to more kg. Any help is appreciated. here is my code below
$("#wUnits").change(function () {
var approx = 2.2;
if ($(this).val() == "lbs") {
value = $("#txtWeight").val() / approx;
$('#wValue').val(value.toFixed(2));
} else if ($(this).val() == "kg") {
value = $("#txtWeight").val() * approx;
$('#wValue').val(value.toFixed(2));
} else {
var value = "";
$('#wValue').val(value);
}
});
and below is my markup
<select id="wUnits">
<option value="">--</option>
<option value="lbs">lbs</option>
<option value="kg">kg</option>
</select>
Ideally what i would like to acheive is a seamless transition between conversions using a dropdown.
What I understand is that you want the conversion to happen not just when you change the value of the <select>
I changed your code a little, it's good to cache the variables in this case, also, I separated the function code to a function named conversion that is triggered on both the <select> change and on keyup or change on your #txtWeight input.
EDIT, implementing Jason Sperske's idea, and added an extra <span> with the resulting units, to avoid confusion. It should be:
HTML:
Convert <input type="text" id="txtWeight" />
<select id="wUnits"><br>
<option value="0">--</option>
<option value="0.45359237">lbs</option>
<option value="2.2">kg</option>
</select><br>
Result: <input type="text" id="wValue" /><span id='rUnits'
JS:
var $units = $("#wUnits");
var $wvalue = $('#wValue');
var $txtweight = $("#txtWeight");
var $runits = $('#rUnits');
$units.change(conversion);
$txtweight.on('keyup change',conversion);
function conversion () {
var value = $txtweight.val() * $units.val();
if(value !== 0) {
$wvalue.val(value.toFixed(2));
$runits.text($units.children(':gt(0):not(:selected)').text());
} else {
$wvalue.val("");
$runits.text('');
}
}
JSBin Demo