Table of Contents

type:
snippet
category:
Add to cart form
name:
Updating a total element to reflect selected price modifiers in your page
versions:
0.6.0, 0.7.0, 0.7.1, 0.7.2, 1.0, 1.1
reference:
http://forum.foxycart.com/comments.php?DiscussionID=3655&page=1
tags:
snippets, shipping, advance
date:
2011-05-26

Updating a total element to reflect selected price modifiers in your page.

  1. Paste the following just before the </head> of any page that requires FoxyCart attribute modifiers calculations.

This is *not* required on the cart or checkout pages, so should not be place in those templates.

Version 0.7.2 and Older

<script type="text/javascript" charset="utf-8">
  //<![CDATA[
  $(document).ready(function() {
    TOTALCLASS = "_total";
    // Create an array to store all the adjustments
    ADJUST = [];
    // Set the handlers for each *_adjust form element
    $("[class$=_adjust]").each(function() {
      var pID = $(this).attr("class").split("_")[0];
      if (typeof(ADJUST[pID]) === "undefined") {
        // Create the array for this product code
        ADJUST[pID] = [];
      }
      switch(this.tagName) {
        case "SELECT":
          // Store the current value
          ADJUST[pID][$(this).attr("name")] = $(this).val();
          $(this).change(function() {
            var pID = $(this).attr("class").split("_")[0];
            ADJUST[pID][$(this).attr("name")] = $(this).val();
            recalcTotal();
          })
          break;
        case "INPUT":
          switch($(this).attr("type")) {
            case "checkbox":
              if ($(this).is(":checked")) {
                  ADJUST[pID][$(this).attr("name")] = $(this).val();
                } else {
                  ADJUST[pID][$(this).attr("name")] = "";
                }
              $(this).bind(($.browser.msie ? "click" : "change"), function () {
                var pID = $(this).attr("class").split("_")[0];
                if ($(this).is(":checked")) {
                  ADJUST[pID][$(this).attr("name")] = $(this).val();
                } else {
                  ADJUST[pID][$(this).attr("name")] = "";
                }
                recalcTotal();
              })
              break;
            case "radio":
              // Store the current value
              if ($(this).is(":checked")) {
                ADJUST[pID][$(this).attr("name")] = $(this).val();
              }
 
              $(this).bind(($.browser.msie ? "click" : "change"), function () {
                var pID = $(this).attr("class").split("_")[0];
                ADJUST[pID][$(this).attr("name")] = $(this).val();
                recalcTotal();
              })
              break;
          }
          break;
      }
    });
    recalcTotal();
  });
 
  function parseAttributes(sValue) {
    sValue = sValue.match(/{(.*?)}/);
    if (sValue) {
      aValue = sValue[1].split("|");
      for(i in aValue) {
        aParts = aValue[i].match(/p([\+|\-|\:])(.+)/);
        if (aParts) {
          return aParts;
        }
      }
    }
    return;
  }
  function recalcTotal() {
    for(p in ADJUST) {
      price = Number($("#"+p+"_price").val());
      adjustment = 0;
      for (a in ADJUST[p]) {
        var aParts = parseAttributes(ADJUST[p][a]);
        if (aParts) {
          var modifier = aParts[1];
          switch(modifier) {
            case ":":
              price = Number(aParts[2]);
              break;
            case "+":
              adjustment += Number(aParts[2]);
              break;
            case "-":
              adjustment -= Number(aParts[2]);
              break;
          }
        }
      }
      price += adjustment;
      $("."+p+TOTALCLASS).html(fc_CurrencyFormatted(price));
    }
  }
  //]]>
</script>

Version 1.0, 1.1

<script type="text/javascript" charset="utf-8">
  //<![CDATA[
  $(document).ready(function() {
    TOTALCLASS = "_total";
    // Create an array to store all the adjustments
    ADJUST = [];
    // Set the handlers for each *_adjust form element
    $("[class$=_adjust]").each(function() {
      var pID = $(this).attr("class").split("_")[0];
      if (typeof(ADJUST[pID]) === "undefined") {
        // Create the array for this product code
        ADJUST[pID] = [];
      }
      switch(this.tagName) {
        case "SELECT":
          // Store the current value
          ADJUST[pID][$(this).attr("name")] = $(this).val();
          $(this).change(function() {
            var pID = $(this).attr("class").split("_")[0];
            ADJUST[pID][$(this).attr("name")] = $(this).val();
            recalcTotal();
          })
          break;
        case "INPUT":
          switch($(this).attr("type")) {
            case "checkbox":
              if ($(this).is(":checked")) {
                  ADJUST[pID][$(this).attr("name")] = $(this).val();
                } else {
                  ADJUST[pID][$(this).attr("name")] = "";
                }
              $(this).bind("change", function () {
                var pID = $(this).attr("class").split("_")[0];
                if ($(this).is(":checked")) {
                  ADJUST[pID][$(this).attr("name")] = $(this).val();
                } else {
                  ADJUST[pID][$(this).attr("name")] = "";
                }
                recalcTotal();
              })
              break;
            case "radio":
              // Store the current value
              if ($(this).is(":checked")) {
                ADJUST[pID][$(this).attr("name")] = $(this).val();
              }
 
              $(this).bind("change", function () {
                var pID = $(this).attr("class").split("_")[0];
                ADJUST[pID][$(this).attr("name")] = $(this).val();
                recalcTotal();
              })
              break;
          }
          break;
      }
    });
    recalcTotal();
  });
 
  function parseAttributes(sValue) {
    sValue = sValue.match(/{(.*?)}/);
    if (sValue) {
      aValue = sValue[1].split("|");
      for(i in aValue) {
        aParts = aValue[i].match(/p([\+|\-|\:])(.+)/);
        if (aParts) {
          return aParts;
        }
      }
    }
    return;
  }
  function recalcTotal() {
    for(p in ADJUST) {
      price = Number($("#"+p+"_price").val());
      adjustment = 0;
      for (a in ADJUST[p]) {
        var aParts = parseAttributes(ADJUST[p][a]);
        if (aParts) {
          var modifier = aParts[1];
          switch(modifier) {
            case ":":
              price = Number(aParts[2]);
              break;
            case "+":
              adjustment += Number(aParts[2]);
              break;
            case "-":
              adjustment -= Number(aParts[2]);
              break;
          }
        }
      }
      price += adjustment;
      $("."+p+TOTALCLASS).html(fcc._currency_format(price));
    }
  }
  //]]>
</script>

Version 2.0+

Click here to see the updated documentation.

Setup

 <input type="hidden" name="code" value="p1" /> 
 <input type="hidden" name="price" id="p1_price" value="20" /> 

Selects:

 <select class="p1_adjust" name="Size">
<option value="10 ml">10 ml</option>
<option value="20 ml{c+test|p+2.50}">20 ml</option>
<option value="20 ml{p+50|c+test}">30 ml</option>
</select>

Checkboxes:

<label for="something">Something</label><input type="checkbox" name="something" value="Yes{p:10|c+test}" class="p1_adjust">

Radio Buttons (note that the grouped radio buttons need to all share the same “name”) :

<input type="radio" class="p1_adjust" name="group1" value="Milk{p:2}"><label>Milk</label>
<input type="radio" class="p1_adjust" name="group1" value="Butter{p:3}" checked><label>Butter</label>
<input type="radio" class="p1_adjust" name="group1" value="Cheese{p:4}"><label>Cheese</label>
 <h4>$<span class="p1_total">20.00</span></h4>

The total would be put into that span element, and as no dollar sign is returned with the value, that is placed outside the span in the h4 element. If you want to use a class that is the code combined with a different string, this can be set at the top of the javscript in the TOTALCLASS variable.

That should be it. The script basically runs through all the elements that have a class ending in “_adjust”, and grabs what the active value is. If that value has a price modifier (p:X, p+X, p-X), it chucks it into an array. After looping over all the form elements, it loops through all the relevent price modifiers, and adjusts the base price and sets the total element. Worth noting is that if you have multiple flat price modifiers (eg p:30) where it alters the base price, only the last modifier is applied, but any plus or minus modifiers are applied after that.