My basic setup is that I have a form, which is hidden, until a selection is made via click, such as “member, nonmember, staff etc.” Once the selection is clicked the form shows, with the the billing area inside also hidden, until the form total reaches greater than $0.
Now the problem I have is that, as soon as 4 of the 5 choices are clicked, the total should instantly be greater than $0. And that being so, the billing portion should trigger automatically, but I can’t get my second function (the one that does the calculations) to listen to the first function for the onclick event or on change event. Is there a way that inside each of my “if” statements, and the end I put in code like “execute calculate function“?
Something like this:
if(section == 'Member') {
var base_cost = 150;
$("#commentTable,#ClinicStaff,#IMSNonMember,#Resident,#Student").fadeOut('slow', function() {
// Animation complete.
});
$("#commentTable, #IMSMember").fadeIn('slow', function() {
// Animation complete
});
$("input[name=SectionChosen]").val('Member');// Section selected, pass as hidden field for processing
***$runNextFunction();***
}
I tried doing: $(" 'input[name^=PROD]', 'base_cost ").change(function() {
to see if I can make the function watch for changes on both the input and the base cost field. But it doesn’t want to trigger. Here is my full setup:
jQuery(function(ready){
jQuery('.showForm').click(function(){
var section = $(this).attr('target');
var base_cost = ''; // reset base cost
$("input[name=TOTAL]").val('');// Reset the Total field to 0 to hide the billing form again
$("input[name^=PROD]").val('');// matches those that begin with 'PROD' and clears them
$("input[name=SectionChosen]").val('');// Reset the section choice
if(section == 'Member') {
var base_cost = 150;
$("#commentTable,#ClinicStaff,#IMSNonMember,#Resident,#Student").fadeOut('slow', function() {
// Animation complete.
});
$("#commentTable, #IMSMember").fadeIn('slow', function() {
// Animation complete
});
$("input[name=SectionChosen]").val('Member');// Section selected, pass as hidden field for processing
}
else if(section == 'Clinic') {
var base_cost = 150;
$("#commentTable,#IMSMember,#IMSNonMember,#Resident,#Student").fadeOut('slow', function() {
// Animation complete.
});
$("#commentTable, #ClinicStaff").fadeIn('slow', function() {
// Animation complete
});
$("input[name=SectionChosen]").val('Clinic');// Section selected, pass as hidden field for processing
}
else if(section == 'Nonmember') {
var base_cost = 250;
$("#commentTable,#IMSMember,#ClinicStaff,#Resident,#Student").fadeOut('slow', function() {
// Animation complete.
});
$("#commentTable, #IMSNonMember").fadeIn('slow', function() {
// Animation complete
});
$("input[name=SectionChosen]").val('Nonmember');// Section selected, pass as hidden field for processing
}
else if(section == 'Resident') {
var base_cost = 75;
$("#commentTable, #IMSMember,#ClinicStaff,#IMSNonMember,#Student").fadeOut('slow', function() {
// Animation complete.
});
$("#commentTable, #Resident").fadeIn('slow', function() {
// Animation complete
});
$("input[name=SectionChosen]").val('Resident');// Section selected, pass as hidden field for processing
}
else if(section == 'Student') {
var base_cost = 0;
$("#commentTable,#IMSMember,#ClinicStaff,#IMSNonMember,#Resident").fadeOut('slow', function() {
// Animation complete.
});
$("#commentTable, #Student").fadeIn('slow', function() {
// Animation complete
});
$("input[name=SectionChosen]").val('Student');// Section selected, pass as hidden field for processing
}
// Calculate order Total
$('input[name^=PROD]').change(function() {
// Total cost of order, is equal to base cost + any additional selectoins made below
var order_total = base_cost;
// Run through all the form fields
$('input[name^=PROD]').each(function(i) {
// Get the current field and its name
var form_name = $(this).attr('name');
// If so, extract the price from the name
var item_price = parseFloat(form_name.substring(form_name.lastIndexOf("_") + 1));
// Get the quantity
var item_quantity = parseInt($(this).val(), 10);
// Update the order total
if (item_quantity >= 0) {
order_total += item_quantity * item_price
}
});
// Display the total rounded to two decimal places
$('input[name=TOTAL]').val((Math.round(order_total*100)/100).toFixed(2));
// Show the billing portion if total is not 0
if (order_total > 1) {
// show the section with the billing portion
$("#BillingPortion").show();
}
else {
// hide billing portion if total is 0
$("#BillingPortion").hide();
}
});
});
});
As you can see from the jsFiddle here the form works, if you click a selection, then add more “cost” by inserting a number into the guests, and THEN the billing portion shows. But that’s not good enough, because if they don’t want any guests, the billing portion should still show if they base cost is greater than $0.
If someone could point me in the right direction that would be great.
Also I’m quite inexperienced when it comes to jQuery, so I’m sure my code could be made more DRY and probably looks awful to some of you, but at least it’s a start.
All right, I went ahead and did a few refactorings on your code. Here’s the result.
Markup of section links
You were using links to switch between forms. However, the links themselves indirectly (through your JavaScript code) set a hidden input called
SectionChosen. You could make it more apparent that clicking a link represents a choice, and that choice is also part of the form data. Therefore, it is much more appropriate to use a set of radio boxes to pick one option, rather than set of semantically unrelated links. Since radio boxes are properinputelements with anameand avalue, these can replace your original hiddenSectionChoseninput. Bonus: you don’t even need any JavaScript to set the value, as the value of the selected radio box will be submitted!Retrieving the base cost
In the
clickhandler, you were trying setting a local variable calledbase_costdepending on the clicked link to calculate the total. The problem is that you were binding new handlers to theinput‘schangeevent, stacking upon previously bound handlers from previously chosen links. It looks like it’s working, but really you’re calculating a multitude of totals with only the last bound handler producing the final output value.In reality, the base cost is a property of the chosen section and it should be readily accessible both when switching sections as when changing form inputs. A good way to do this is by storing the base cost of each choice as an attribute on the radio box.
data-*attributes were introduced specifically for such custom data needs:The base cost can then be retrieved with:
To get the base cost from the currently selected section, simply look for the currently selected radio box:
That’s all there is to it! You no longer need to bind the
changehandler from within theclickhandler, as you can find the base cost in the markup itself. This means you only need to bind thechangehandler once at DOM ready, as it should be.Further improvements
There’s always room for more improvement. For example, you could give the actual form sections a
data-sectionattribute matching the section name instead of anid. This way, you can more easily select the sections which need to be hidden and those that need to be shown. Instead of writing down the same list of ID selectors, you can just select something like.section[data-section="Member"]and.section:not([data-section="Member"]). Heck, thatdata-sectionvalue can even come from the chosen radio box itself, you won’t even need a longif...else iftree any more!