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 and newer

<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>
  • Setup your forms like so:
  • Every FoxyCart based product that have product modifiers needs to have a unique code set like:
 <input type="hidden" name="code" value="p1" /> 
  • Give your hidden price input an id that combines your code and “_price” like:
 <input type="hidden" name="price" id="p1_price" value="20" /> 
  • Any select, checkbox or radio element needs to be given a class that combines your code and “_adjust” like:

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>
  • Set an element to be where the total cost is shown and updated, by combining the code and “_total” as its class, like:
 <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.

Site Tools