I have this piece of JavaScript that will sum up a totalprice based on radio/checkbox selection
JQUERY
var price = 0;
$('.price-input').click(function () {
if ($(this).is(":checked")) {
price += parseInt($(this).attr("data-price"), 10);
$('.total-price').text(price);
$('.total-price-input').val(price);
} else {
price -= parseInt($(this).attr("data-price"), 10);
$('.total-price').text(price);
$('.total-price-input').val(price);
}
});
The HTML is a collection of 3 radiobuttons and 3 checkboxes, where the radiobutton is one price and the checkboxes can sum up 3 prices with the radiobutton price to give a total price.
<input class="price-input" data-price="2000" id="ChosenLane" name="ChosenLane" type="radio" value="Konference - Spor 1: Lean">
<input class="price-input" data-price="1300" id="ChosenLane" name="ChosenLane" type="radio" value="Konference - Spor 2: Innovation">
<input class="price-input" data-price="1600" id="ChosenLane" name="ChosenLane" type="radio" value="Kage">
<input type="checkbox" name="lanes" value="Aften buffet" data-price="1000" class="price-input">
<input type="checkbox" name="lanes" value="fthrctfyh" data-price="5456" class="price-input">
<input type="checkbox" name="lanes" value="dfhxfhg" data-price="54545" class="price-input">
All in all this works - if I select a radiobutton it will add the radiobutton price to the price, but if I click a radiobutton again it will add the price again to the totalprice. I want the radiobuttons, not to add if one is selected, but instead just use its price.
So if I check a radiobutton it will at 2000 to the price and if I click another radiobutton, it will subtract the 2000 and add 1300 instead.
Please check the following solution:
JQUERY
$(function () {
$('.price-input').change(function () {
var price = 0;
$('.price-input').each(function(){
if ($(this).is(":checked")) {
price += parseInt($(this).attr("data-price"), 10);
}
})
$(".totalPrice").text(price);
});
})
Fiddle: http://jsfiddle.net/kkqqfaqv/
Change your code to change event from click event. As click event is called every time user clicks the radio box, doesn't matter whether selected or not. Change event will be triggered if the state of checkbox changes
I am not entirely clear about your relation betweeen price and total-price-input.
As a general rule for much higher robustness: Don't rely on clean unsetting-setting, i.e. that substracting X and adding Y always match up one on one.
Rather:
always start your callback function with price=0
check which input buttons and radio button are set
add up accordingly
This has also the benefit, that you can trigger such a clean-from-start calback after page DOM load: I.e. if user goes browser-forward, then back, inputs and radio buttons keep being checked (in any modern browser) ➠ having the correct value for that resurrected choice (rather than 0 and a “refresh problem” is good. ➠ Thus put it in a named distinct function, to call upon $.ready() and upon .change().
Also, I'd use .change() rather than .click(): Input can possibly change state by other means than click (like keyboard navigation?), and change is what you are looking for.
Related
Background
I'm not the hottest jQuery guy out there by a very long shot and I'm trying to strip out the repeated work in the below code. Whilst the performance overhead is probably minimal and negligible - this is more a case of not wanting to write crappy code that does the same thing several times.
Basically I have a simple invoice form, that a user can add multiple items too.
The form initially has 4 inputs: Item Name, Item Price, Item Quantity and Total
The total is calculated whenever the Price or Quantity field fires a change event
Problem - Partially resolved (See Update)
The user can add an additional row of inputs for a second (or third, fourth, fifth, etc...) item
The existing javascript which attaches the event handler to the price and quantity fields has already run so will not attach listeners to the newly added row of inputs.
Solution ?
Currently I've hashed out something horrible whereby after adding the new row of inputs I re-attach an event listener to all input fields.
That's cool I guess, if you take no pride in the quality of your work, but if the invoice is 20 items do I really need to on adding the 20th item row loop over the 19 rows that already have listeners attached, attach them again and then attach listeners to the new row. I would hope not.
I've already managed to target the newly added row of inputs to wipe the values from the cloned inputs - so I'm thinking just target the new input fields and attach listeners - but I'm getting in a right two and eight because ideally I'd like to do this like so
Clone the input row
Clear the values
Attach listeners
Add to the DOM
What I'm currently doing which feels grotesque is
Clone the row
Add the row to the DOM
Select the newly added row and wipe the values
Select the newly added Quantity field and attach a listener
Select the newly added Price field and attach a listener
Select the newly added Total field and attach a listener (to update the invoice total)
Code below, for you to laugh at and then hopefully take pity on me and provide a more succinct solution or at least a suggestion as to how to go about writing my own better version.
/** Add additional item lines */
$('#add-item').click(function(e){
e.preventDefault();
/** clone first line and insert it */
$('.input-row:first').clone().insertAfter('.input-row:last');
/** clear the newly inserted inputs of values */
$(':input', '.input-row:last').val("");
/** ensure all item price and qty inputs have events attached to their change value */
$('input[name="item_qty[]"],input[name="item_price[]"]').on("change",function () {
var $container = $(this).closest('.form-group');
qty = Number($('input[name="item_qty[]"]',$container).val())||0,
price = Number($('input[name="item_price[]"]',$container).val())||0;
$('input[name="item_total[]"]',$container).val(qty * price);
$('input[name="item_total[]"]',$container).change();
});
/** Sum inputs for invoice total */
$('input[name="item_total[]"').change(function() {
var total = 0;
$.each($("[name='item_total[]']"), function(index, value) {
total += parseFloat($(this).val());
});
$("#total").val(total);
});
});
Update
So by utilising event delegation, events propagate (or bubble) up the dom - thanks guys! I've got the invoice total being recalculated any time one of the inputs within the new parent div change
<div id="invoice-items">
<input name /> <input quantity /> <input price /> <input total />
<input name /> <input quantity /> <input price /> <input total />
<input name /> <input quantity /> <input price /> <input total />
...
</div>
/** if any input rows change update the invoice total */
$('#invoice-items').on('change', 'input', function(event){
var total = 0;
$.each($("[name='item_total[]']"), function(index, value) {
total += parseFloat($(this).val());
});
$("#total").val(total);
});
Problem I'm left with...
I'm still stuck on how I go about updating <input total /> to reflect the changes to that particular line. I'm guessing somewhere in my new jQuery snippet I need to determine which field changed and update the total on the same row ?
This is how I'm currently attaching the change listeners to the first / existing row of input to populate the line total
/** calculate item total */
$('input[name="item_qty[]"],input[name="item_price[]"]').on("change", function () {
var $container = $(this).closest('.form-group');
qty = Number($('input[name="item_qty[]"]',$container).val())||0,
price = Number($('input[name="item_price[]"]',$container).val())||0;
$('input[name="item_total[]"]',$container).val(qty * price);
$('input[name="item_total[]"]',$container).change();
});
I guess what I still need is some means to run this code after a line has been added, or following the cleaner event delegation route - some way to target just the item_total[] for the row in which the change event happens ? Maybe I can capture the specific index of the element on which the change event is fired - and update only the item_total[] at that index ?
Just thinking out loud here, I guess if I capture the event and loop through all of the inputs til I find that element which matches the element the event was fired from I could then grab the next form input with the name invoice_total[] and update it ? - let's go check.
Update
So I can capture the event - happy days :)
event.currentTarget.attributes.name.nodeValue == 'item_qty[]'
So I still don't know which of the item_qty[] elements I've updated and therefore I don't know which item_total[] element to update.
Any suggestions guys ?!?
You want to take the wrapping element
<div>
<input />
<input />
</div>
$('div').on('change', 'input', function(){
// your magic here
});
This will work on the two who are there now, and new elements as well. Why? Simply put:
You bind the events to elements that exists. You make a new one, change it, but never bound the event to the new elements. The event bubbles up the tree, nothing to catch it.
My code doest bind to the elements itself, your telling it to listen to changes in it on input. New elements come in, you change them, nothing happends, so it bubbles up the tree.
And this is the big difference: this time we told the existing element to do something now.
I'm working on this eCommerce project where I need to calculate "shipping costs" if a particular checkbox is checked.
Here's the code for the checkbox :-
<div class="alert alert-info">
<p>Shipping Outside Lagos (N2, 000)</p>
<input type="checkbox" name="shipping" id="shipping">
</div>
How can I write the jQuery function, so that when the input is checked..I can get the value in a variable. Suppose the default value is 2000, how would I be able to get $amount=2000 (if checked) and $amount remains 0 if unchecked.
Due to my limited knowledge in jQuery / JavaScript, I'm unable to find a solution for it.
Search didn't help either.
Any suggestions are welcome.
var amount = $('#shipping').is(':checked') ? 2000 : 0;
$('#shipping').on('change', function() {
amount = this.checked ? 2000 : 0;
});
// use amount
You can do:
var shippingAmt = 0;
$("#shipping").change(function() {
shippingAmt = this.checked ? 2000 : 0;
});
I'd suggest using a function to determine the cost of items. You could have an abstract of determining costs which would run through a few or several conditions to calculate 'add ons' so to speak.
So you'd have your initial total of say $500.99, then run that value through something like calculateTotalValue(value)
It would check if any add-ons were checked in the form, and add their values to the initial value.
This would allow you to have any number of extras, like shipping, or even add-ons/upgrades for the product itself, and you'd be able to fetch the total without fail in each case. You could have a generic way of stipulating that a field is an 'add on' so you wouldn't need to maintain a list, like so:
<input type="checkbox" rel="add-on" data-add-on-type="shipping" value="500">
Then in your function,
calculateTotalValue(value) {
$.each($('input[rel="add-on"]'), function(i) {
// You probably want some error checking here
value += this.val();
});
return value;
}
If necessary you could use data-add-on-type to keep track of where costs comes from to output a list for the user, as well.
I'm currently working on a restaurant menu ordering website and I am stuck on adding dish options to certain dishes. I use radio buttons to let the user choose their preferred option:
<label class="option"><input type="radio" value="Ketchup"> Ketchup</label> etc ...
Then, I have an add button which is an link with an onclick attribute which then runs a function. How can i pass the checked radio box value through the function without a form ?
When you click the add button, it has no idea what radio button got selected, so you can't really "pass the checked radio box vale through". What you can do though is just check the value from inside the function, if you give your radios a class that lets you reference them. With a class of say "dish", the jquery code for that would be:
$('.dish:checked').val();
If you give your form elements IDs, like so:
<label class="option"><input type="radio" id="radioButton1" value="Ketchup"> Ketchup</label>
Then you can easily access the values of your radio buttons through the DOM. I would not use a parameter but a local variable, like so:
function myFunction {
var myValue;
if (document.getElementById('radioButton1').checked == true) {
myValue = document.getElementById('radioButton1').value;
}
else {
// Check other radio buttons
}
// Perform some function using myValue
}
Give the input "Radio Buttons" an id with an onClick event on each one that, when the button is clicked, will run the function the event is attached to.
Hi i have a radio button(StarRating radiobutton using jquery) and a textbox. When i click on the star, i would like the radiobutton value to display to the textbox.
<input id="InsRating1" class="star" type="radio" name="InsRating" value="1" title="Worst"/>
<input id="InsRating2" class="star" type="radio" name="InsRating" value="2" title="Good"/>
I tried put the Onclick() in the but onClick() has never get fired.
Please advice how to get the value from my radiobutton to textbox. Thanks
I tried this below, but the value is "Undefined"
$(document).ready(function() {
$('#InsRating1').click(function() {
alert(this.value)
});
});
-------------Edit----------
I am using g_thom's answer below but come to this problem :
I have 3 set of stars with 3 textboxes. Each rating should show to only 1 textbox.
However whenever any star is clicked, it shows the value to all 3 textboxes instead of just specified one. Please advice. Thanks
<script type="text/javascript">
$(function() {
$('.star-rating').click(function() {
// assign the value of "total stars" to a textbox with an id of ratingText
$('#EvaluationInstructorRatingTextBox').val($('.star-rating-on').length);
});
$('.rating-cancel').click(function() {
// the value is '0' when the cancel button is clicked
$('#EvaluationInstructorRatingTextBox').val('0');
});
$('.star-rating').click(function() {
// assign the value of "total stars" to a textbox with an id of ratingText
$('#EvaluationMaterialRatingTextBox').val($('.star-rating-on').length);
});
$('.rating-cancel').click(function() {
// the value is '0' when the cancel button is clicked
$('#EvaluationMaterialRatingTextBox').val('0');
});
$('.star-rating').click(function() {
// assign the value of "total stars" to a textbox with an id of ratingText
$('#EvaluationValueRatingTextBox').val($('.star-rating-on').length);
});
$('.rating-cancel').click(function() {
// the value is '0' when the cancel button is clicked
$('#EvaluationValueRatingTextBox').val('0');
});
});
Since the inputs are converted to divs (with the 'rated stars' being assigned a different class), I think you'll want to count the number of divs with the .star-rating-on class and assign that value to the input, like this:
$('.star-rating').click(function() {
// assign the value of "total stars" to a textbox with an id of ratingText
$('#ratingText').val($('.star-rating-on').length);
});
Boring looking example - without the actual graphics/animations (just the HTML from the transformed inputs on plugin page - the value will always be 4): http://jsfiddle.net/bhf2d/
EDIT
The code above should work. I think you may be thinking that you need to apply your jQuery to the radio button, but that's not the case, since it is swapped out on page load with a div. Just in case you're not clear, I've added a live example using the code you provided in your question: Click here to see it.
EDIT 2
See an updated version here, matching the additional requirement to set multiple checkboxes. The textboxes have been renamed slightly (InsRatingText0 etc) to facilitate easily adding more items. The name convention InsRatingText[n] is set that way to match the div classes the plugin adds dynamically ('rater-0', 'rater-1', etc)
These <input> elements are not clicked, since they are hidden and replaced by <div> elements. You should use onChange() events instead.
Also, radio button do not use the property value, but checked.
Try something like this
$(function (){
$(".star").click(function(){
$("#textbox1").val($(this).val());
});
});
Basically, it is adding a handler for onclick to the eloement with class ="star" and then copying that value to the textbox.
$(".star").bind('click', function() {
$("#ratingValue").val($(this).text())
});
Seems like getting the val() on the checkbox didn't work, but using text() gives the value. Here is the example working: jsfiddle
I'm fairly new to JavaScript and am trying to write some code that lists three price options in a form, as checkboxes. If both of the first two are selected, I want the total price to drop by a certain amount.
My code is based on the code in this question:
Javascript checkboxes incorrect calculating
They reset the base value by a date variable. I assume that if I have a function that sets the base to a negative value if those two boxes are checked, that would achieve what I want. I'd also like the output to have an additional tag of 'save (x) per month' when this happens.
However I'm not sure how to go about relating the variable to the checkboxes.. do I need to use jquery as per how to change the value of a variable based on a select option:selected?
Jquery is never necessary, but it is always a plus. since you are learning javascript, i would recommend not using the framework yet.
First you need a form (it would be better if you showed us what your form looks like):
<form>
<input type="checkbox" id="first" /><label for="first">First Box</label> <br>
<input type="checkbox" id="second" /><label for="second">First Box</label> <br>
<input type="text" id="output" value="5.00"/>
</form>
Now the javascript
<script type="text/javascript">
var first = document.getElementById("first");
var second = document.getElementById("second");
first.onchange = function () {
if (this.checked == true) {
document.getElementById("output").value = "new Value";
}else {
document.getElementById("output").value = "other Value";
}
}
... the same can be done for 'second' ....
</script>
I'm assuming you are modifying your recalculate() function from your earlier question. In that function, after you get your sum, add this to apply the discount:
if ($("#chkBox1,#chkBox2").filter(":checked").length == 2)
{
sum -= discount;
}
To write the message to your output, modify your $("#output").html(sum) code to this:
$("#output").html(sum + " Save $" + discount + " per month");
if (document.getElementById('checkBox1').checked && document.getElementById('checkBox2').checked) {
// Change the price
}
There are many ways to address this issue. As a reminder before I get into it, never do something like 'calculating price' on the client-side. That is, you can calculate the price so show the user, but any real calculations should be done on the server side (as clients can adjust and manipulate form submissions).
I created a simple example that will tally the results of checked checkboxes (and simply displays the result). There are lots of ways you can manipulate this code to fit your purpose. I have used jQuery, but there are other interesting options for this problem (check out KnockoutJS, for instance).
<input type="checkbox" class="adjust one" data-value="1.00" id="so1" /> <label for="so1">$1.00</label> <br/>
<input type="checkbox" class="adjust two" data-value="2.00" id="so2" /> <label for="so2">$2.00</label><br/>
<input type="checkbox" class="adjust one" data-value="3.00" id="so3" /> <label for="so3">$3.00</label>
<p>
Total: <span class="total"></span>
</p>
Then, you want to include the following JavaScript (along with the jQuery library).
var total;
var calculateTotal = function() {
total = 0.0;
$('input[type="checkbox"]:checked').each(function() {
total += parseFloat($(this).data('value'));
});
$('.total').text(total);
};
$(document).ready(function() {
$('input[type="checkbox"]').live('change', function() {
calculateTotal();
});
calculateTotal(); //do it for initial price
});
calculateTotal() will calculate a total based on the checkboxes (inputs of type checkbox) which match the selector "checked". This then pulls the data attribute "value" from each checkbox and calculates a total based on that number. The logic for your problem is likely to differ, but simply adjusting calculateTotal should handle this. Finally, the calculateTotal function gets called whenever a checkbox is 'changed' (and once initially).
Hopefully this should be a big help in getting you up and running. Here is a JSFiddle live demonstration.