Documentation You are here: start » v » 1.1 » javascript

FoxyCart's Javascript: foxycart.js

FoxyCart's foxycart.js file is full of goodies that you probably won't ever need to think twice about. If default configurations are an anathema to you, if you need to get advanced for a custom integration, or if you're just curious about what's under the hood please explore this page and the “raw” version of the foxycart.js, and let us know if you have any questions.

What It Does

The foxycart.js file:

  • Handles all cross-domain sessions, ensuring sessions don't get lost regardless of browser privacy settings (so long as some cookies are enabled).
  • Automatically (mostly) handles determining at what level to set your store's FoxyCart cookie. (ie. Determines to set it at .example.com or .example.co.uk or .custom.example.com.)
  • Makes it easy for custom events or validation to be run before products are added to the cart.
  • Makes it easy for custom events on an attempted add-to-cart (ie. the default Colorbox modal window, custom JSONP functionality, etc.).
  • Makes it easy for custom events or validation to be run after products are added to the cart.
  • Automatically attaches onclick and onsubmit handling to all links and forms (even dynamically created elements) pointing to your store's FoxyCart cart URL.
  • Keeps the FoxyCart JSON object (FC.json) current before and after cart requests.
  • Alerts if jQuery isn't loaded.

Available Files

  • http://cdn.foxycart.com/YOURDOMAIN/foxycart.colorbox.js: Compressed. Includes the code to automatically set your store's domain, your store's FoxyCart domain, to initialize the FC object as fcc, and to attach Colorbox to all add-to-cart links and forms.
  • http://cdn.foxycart.com/YOURDOMAIN/foxycart.js: Compressed. Includes the code to automatically set your store's domain, your store's FoxyCart domain, and to initialize the FC object as fcc. Note that the preprocess and process events don't actually have any behavior in this version of the file, and that postprocess is not referenced at all, since postprocess should be called by whatever process events you've defined.
  • http://cdn.foxycart.com/YOURDOMAIN/foxycart.raw.js: Uncompressed. Does not set your store's domain, your store's FoxyCart domain, nor does it initialize the fcc object. This will generally only be used for special circumstances or advanced users needing access to the uncompressed code.

What's Different from Previous Versions

Almost everything but some of the ways that sessions are set has been rewritten, but here are the main changes from the foxycart_includes.js in v0.6.0:

  • No more .foxycart class necessary for add-to-cart links and forms. Instead it relies on the href or action of the link or form pointing to your FoxyCart's domain.
  • The fc_json object is now accessible as FC.json.
  • fc_PreProcess() has been changed to a preprocess() method that's more flexible, called differently, expecting different arguments.
  • fc_BuildFoxyCart() has similarly been changed to a postprocess() method described below.
  • Setting the FoxyCart Session ID (fcsid) at a subdomain, third-level domain, or specific path is now possible without rewriting core functions.
  • fc_AddSession doesn't exist anymore, the current session can be retrieved using fcc.session_get(). Note that the new javascript uses jQuery's live() event to find any links or forms that are directed at FoxyCart and adds the session to them automatically, so you don't generally have to use this. If you are altering the href of a link dynamically though, you will need to re-add the session to the updated href, otherwise FoxyCart will assume its a new link and you'll get double ups on the process functions (ie: 2 carts in colorbox).
  • fc_tb_show doesn't exist anymore as 070 now uses colorbox as the default modal window. If you check out the foxycart.js you add to your page, you can see the colorbox being initialized there. Its just a vanilla colorbox implementation so you can use colorbox for whatever else you need modals for too.

How It Works & Configuration

While most of this should happen automatically, especially if you're using the foxycart.js or foxycart.colorbox.js versions (as opposed to the foxycart.raw.js), there are a few things that need to be configured correctly.

jQuery Dependency: The sample code found in Admin » Sample Code includes jQuery 1.9.0. If you are already working with jQuery and have an older version, we recommend that you update to at least 1.9.0. If for some reason you cannot, please test thoroughly. Make sure that only one instance of jQuery is included on your page otherwise you will get strange errors that can be hard to diagnose.

The first configuration that the FC object in foxycart.js takes is the path to your store's FoxyCart cart, like yourstorename.foxycart.com. This setting is critical (and usually set automatically unless you're using the “raw” version of foxycart.raw.js), as this is how the script determines which links to attach the click or submit events to, as well as when and how to add the session ID to any and all requests to your store's FoxyCart requests.

Without this setting configured correctly it is highly likely that your customers will lose their cart contents when they attempt a checkout.

''sitedomain'': The Domain on Which Your Visitor's FoxyCart Cookies Are Set

The sitedomain is the second argument required, but unlike the storedomain, the sitedomain is only used to determine where to set the cookie for the visitor's FoxyCart session. If your sitedomain is passed in as example.com or www.example.com, the fcsid (FoxyCart Session ID) cookie is set at the second-level domain, which is .example.com. If your sitedomain is a third-level domain like example.co.uk or subdomain.example.com, the cookie would be set at .example.co.uk or .subdomain.example.com.

This setting is only important if your site isn't at the second-level domain, or if you want to restrict your FoxyCart sessions by subdomain. For example, if your site is example.co.uk, you don't want the cookie set at .co.uk. Or if you want to have different FoxyCart sites at donations.example.com and products.example.com, you'd need the cookies not to be set at .example.com or the sessions would overlap with unexpected results. (Another example would be if your site is at a 3rd party provider like example.squarespace.com, you don't want all *.squarespace.com sites sharing your FoxyCart sessions.)

The only two things to keep in mind are:

  1. The www subdomain is effectively ignored, so if you do want to lock your sessions down to .www.example.com you'll need to set the sitedomain value to something like www1.example.com. The actual value doesn't matter; it's only counting the dots in the value after it strips the www.
  2. You cannot have the FoxyCart javascript at any other subdomains if you are isolating by subdomain. For example, if you have two separate stores at products.example.com and donations.example.com you cannot also have your foxycart.js at www.example.com or example.com, as that will set the session cookie at .example.com, which will override the products and donations session cookies.

Example: If you're testing two different sites at subdomains of the same domain (like store1.example.com and store2.example.com), you'd put this script tag before the FoxyCart script tag:

<script type="text/javascript" charset="utf-8">
	var sitedomain = 'store1.example.com';
</script>

Note: You probably wouldn't want to keep this in production, unless the site only lives at a subdomain, and is never available at the example.com top level domain.

''cookiepath'': The Path on Which Your Visitor's FoxyCart Cookies Are Set

The cookiepath determines the fcsid cookie's path. This is almost always going to be empty, so the cookies would be set at .example.com, but if you do need to have multiple FoxyCart sessions on the same domain you could use this setting to restrict cookies to something like .example.com/en/ and .example.com/es/ (to split English and Spanish FoxyCart stores, for example).

The cookiepath value must end in a / or you may run into issues, especially with Internet Explorer. The leading slash is automatically applied by the foxycart.js, so if you want a path of /en/ you would enter cookiepath = 'en/';.

Example: Suppose you have a donations section and a bookstore, located at http://example.com/donations/ and http://example.com/bookstore/. (Note that the trailing slash is critical. If you have something like http://example.com/bookstore and http://example.com/donations this method will not work and the sessions will collide.) Add the following code before your calls to foxycart.complete.js or foxycart.js. Obviously, change out the “donations” with “bookstore” depending on where you're placing this code.

<script type="text/javascript" charset="utf-8">
	if (typeof(cookiepath) == 'undefined') {
		var cookiepath = 'donations/';
	}
</script>

Helper Functions

Loading the Cart on Page Load

If you find yourself needing to have the default Colorbox-powered FoxyCart cart load itself when your site is loaded, the foxycart.colorbox.js file has a helper function that loads the cart with a cart=view command. To accomplish this, simply link to a page on your site (one that has the foxycart.colorbox.js linked on it) with fc_open=true in the anchor. So the href in a link to your site might look like this:

http://example.com/landing_page.html#fc_open=true

That will call fcc.events.cart.process.execute with your FoxyCart cart's “view” parameter.

"Mini-Cart" Display and HTML Helper Functionality

When the FC class is initialized (via the .init() method) and on the .cart_update() method, elements with the following classes or IDs are modified:

  • #fc_minicart, .fc_minicart: If the FC.json.product_count is greater than 0, these elements will be shown. Otherwise they'll be hidden
  • #fc_quantity, .fc_quantity: The inner HTML will be replaced by the value in FC.json.product_count.
  • #fc_total_price, .fc_total_price: The inner HTML will be replaced by the value in FC.json.total_price, formatted using the _currency_format function (which adds decimals but doesn't add currency symbols).
  • #fc_singular, .fc_singular: The inner HTML will be shown if value in FC.json.product_count is equal to 1, and is hidden otherwise. It can be useful if you want to show “Item/Product” instead of “Items/Products” for FC.json.product_count = 1.
  • #fc_plural, .fc_plural: The inner HTML will be shown if value in FC.json.product_count is greater than 1 or less than 1 (zero), and is hidden otherwise.
<a href="https://yourdomain.foxycart.com/cart?cart=view" id="fc_minicart">
	<span id="fc_quantity">0</span>
	<span id="fc_singular"> item </span>
	<span id="fc_plural"> items </span> in cart
</a>

''session_get'' Appending the FCSID to Requests

What It Is

The fcsid (FoxyCart Session ID) cookie stores the unique session ID of the customer, and is arguably the most important piece of a FoxyCart implementation. If the fcsid isn't sent to FoxyCart when the cart is requested, the customer will lose the entire contents of their cart, and may see other errors as well.

How It Works: Overview

When a webpage with foxycart.js loads, foxycart.js attempts to set a fcsid cookie according to the sitedomain and cookiepath values discussed above. Most of this is handled automatically

How It Works: Details

The session_get method will look for and set an fcsid cookie with the value retrieved from (in this order):

  1. A hash in the loaded URL (ie. #fcsid=abc123).
  2. An fcsid cookie.
  3. The FC.session_id in the JSON.

How To Use It: JSONP and Dynamically Modified Elements

If you're generating actions (cart-adds, JSONP requests, dynamically changing an add-to-cart link's href, etc.), you'll need to manually add the fcsid to your request. Luckily, this is fairly easy with the session_get() method. Assuming a normal foxycart.complete.js or foxycart.js inclusion in your template, you would create the link or JSONP URL like this (in javascript):

// Just the link to the cart itself
var cart_request = 'https://'+storedomain+'/cart?'+fcc.session_get();
// Adding a product
var cart_request = 'https://'+storedomain+'/cart?name=Test_Product&price=9.99'+fcc.session_get();
// Retrieving the cart via JSONP
jQuery.getJSON('https://'+storedomain+'/cart?'+fcc.session_get()+'&output=json&callback=?', function(data) {
	// callback function goes here
});

The fcc.session_get() call will return something like &fcsid=abc123su2eoba8r9oknf7qa4b3. If you just need the fcsid value itself you can easily retrieve it from the JSON with FC.session_id.

Developer Note: if you are developing with Chrome and on an IP address, Chrome won't let you save cookies to that IP or to localhost so it's best to do any session_get() calls with another browser during development. http://code.google.com/p/chromium/issues/detail?id=56211

Are you creating or modifying elements? If you're dynamically creating add-to-cart links or forms, you don't need to bother with this at all. It will be handled automatically. If however you're modifying the href of an add-to-cart link that was present on pageload you do need to append the fcsid. This has to do with how FoxyCart binds onclick handlers to elements while also making it easy to add new add-to-cart link or form elements.

Adding Your Own Events

The following “events” below have the following methods:

  • add: Adds the function to the event's function array.
  • add_pre: Adds the function to the event's function array before any other functions in the array.
  • resume: Resumes a previously “paused” event. If pause is returned, execution of the event function array stops, but it keeps its place. This is very useful if you need to ensure that an asynchronous request has completed before proceeding.
  • execute: Execute's all the functions in the array, stopping if false is returned. (This is mostly an internal method, and won't likely be used by even very advanced integrations.)

If you want to keep the colorbox modal implementation and extend with custom events be sure to add any fcc customization after that. (You don't need to include both foxycart.js and foxycart.colorbox.js, as foxycart.colorbox.js has the entirety of foxycart.js inside of it already.)

<script src="//cdn.foxycart.com/YOURDOMAIN/foxycart.colorbox.js?ver=2" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
fcc.events.cart.preprocess.add(function(e, arr) {
	console.log(arr);
	return true;
});
</script>

''ready'': When the Cart is Ready on Pageload

What It Is

If you need to execute javascript on pageload, but you require the cart contents, the ready event will allow you to execute code once the FoxyCart cart object is ready.

How It Works: Overview

When the foxycart.js is loaded on a page, it will retrieve the cart data when the page is ready (on jQuery's document.ready event).

How It Works: Details

Unlike the other events, the ready event's execute() method does not get called with any arguments.

''preprocess'': Before an Add-To-Cart

What It Is

Attaching a custom event to be run before an item is added to the cart can be useful if you need to do client-side validation of a form or value before allowing the cart-add to happen. For example, you may have a “Custom Note” field on an add-to-cart form that's required. Or a “Gift Recipient Email Address” field that must be completed for the item to be added to the cart. Using the preprocess event allows all of this and more.

How It Works: Overview

When a link or form pointing to your FoxyCart's cart URL (ie. https://example.foxycart.com/cart) is clicked or submitted, foxycart.js first checks to see if any functions have been added to your preprocess array. If any functions exist, they are run in order of entry (first-in-first out) passing in two arguments:

  1. The submitted element itself.
  2. An array of name/value pairs to be submitted to the cart-add request. This array is built using an “unserialize” function inside the FC object.

If any function in the preprocess array returns false, the cart-add is aborted. (The actual onclick or onsubmit event of the add-to-cart link or form returns false, so the default behavior of the element is bypassed as well.) No other indication is given, so if you have a preprocess function that returns false it should also alert the user.

If no preprocess functions are added, this step is effectively skipped.

How It Works: Details

Assuming the default fcc object, the first step is to create a function and add it to the preprocess array:

foxycart_ga = function(e, arr) {
	var href = '';
	if (e.tagName == 'A') {
		href = e.href;
	} else if (e.tagName == 'FORM') {
		href = 'https://'+storedomain+'/cart?'+jQuery(e).serialize();
	}
	if (!href.match("cart=(checkout|updateinfo)") && !href.match("redirect=")) {
		pageTracker._trackPageview('/cart');
		console.info('foo1');
		return true;
	}
}
fcc.events.cart.preprocess.add(foxycart_ga);

Or just create an anonymous function straight in the array, like this:

fcc.events.cart.preprocess.add(function(e, arr) {
	var href = '';
	if (e.tagName == 'A') {
		href = e.href;
	} else if (e.tagName == 'FORM') {
		href = 'https://'+storedomain+'/cart?'+jQuery(e).serialize();
	}
	if (!href.match("cart=(checkout|updateinfo)") && !href.match("redirect=")) {
		pageTracker._trackPageview('/cart');
		console.info('foo1');
		return true;
	}
});

That function fires off a request to Google Analytics's _trackPageview() function before the cart is added, and returns true. Because it returns true the .execute() method of the preprocess object will continue on to the next function in its array. If the execute() method runs all the functions in the preprocess array without hitting a return of false, the cart-add request moves on to the process event.

''process'': The Actual Add-To-Cart Event

What It Is

The process event is where you can define what happens when a visitor to your site clicks an “add to cart” link or form. You may want to display an unobtrusive indication that the item has been added to their cart; you may wish to display a modal window (like the default Colorbox script); you may want to send the visitor directly to checkout if certain products are in the cart; or you may want to do a combination of all that and more. All of this functionality can be defined in the process event.

Skipping It Entirely

If you don't want anything fancy and just want your links and forms to load the cart up straight, just don't add any functions to process. It's that easy. If no functions are present then your add-to-cart links and forms will behave normally.

How It Works: Overview

The process functionality is nearly identical to the preprocess functionality described above, but whether true or false is returned may be a bit more nuanced. Generally you'll only want _one_ event in the process array, though you can have more if necessary.

One thing to keep in mind is that a return false; is probably desired if you actually do anything here, such as a JSONP request or a modal window call, since that is where the item is added to the cart. If you don't return false then the add-to-cart link or form will fire and the request will likely be duplicated.

How It Works: Details

After any preprocess events have been run, the process event is first checked to determine if any functions have been added. If the process array is empty, true is returned and the default behavior of the add-to-cart element that was submitted continues.

Adding a function to the process array is the same as with the preprocess examples above, but obviously replacing preprocess with process. Here's an example of the way Colorbox is attached to cart-add requests in the default foxycart.complete.js file:

fcc.events.cart.process.add(function(e){
	var href = '';
	if (e.tagName == 'A') {
		href = e.href;
	} else if (e.tagName == 'FORM') {
		href = 'https://'+storedomain+'/cart?'+jQuery(e).serialize();
	}
	if (href.match("cart=(checkout|updateinfo)") || href.match("redirect=")) {
		return true;
	} else {
		jQuery.colorbox({
			href: href,
			iframe: true,
			width: "700px",
			height: "70%",
			onClosed: function(){fcc.events.cart.postprocess.execute(e);}
		});
		return false;
	}
});

This example first checks to see if the element that was submitted is a link (A) or form (FORM). It then sets the URL to be submitted to the cart. If that cart request should bypass the cart, however, it returns true, thus allowing the link or form to complete its behavior unimpeded (and bypassing the modal window entirely). If the cart-add request does belong in a modal window the code instantiates a Colorbox and loads the cart in an iframe. It then returns false, preventing the link or form from submitting again (since loading it in the Colorbox's iframe has already made our cart request.

Notice the onClosed function. That comes next. Onward, ho!

''postprocess'': After the Add-To-Cart

What It Is

The postprocess event is not called directly by foxycart.js, but is available to use if you need it. This can be useful, for example, if you want to refresh the FC.json when your modal window is closed, as is the case with the default foxycart.colorbox.js.

How It Works: Overview

Just like the preprocess and process, you can add multiple functions to the postprocess even. Notice the call to postprocess in the process example above, in the onClosed parameter. That's telling Colorbox to run the postprocess events when the modal window is closed. If we add a function like below, then the cart_update() method will be called (which refreshes the FC.json and updates the “minicart” helper functions).

	fcc.events.cart.postprocess.add(function(){
		fcc.cart_update.call(fcc);
	});

(The .call(fcc) is necessary to prevent the this keyword in JavaScript from going wonky.)

Pausing and Resuming Event Execution

The need for pausing and resuming an event is most often seen in adding products to the cart. Sometimes you may need to add or remove a product silently before a cart request is sent, or you may need to add custom fields to the session for affiliate or analytics tracking. Because JavaScript is a non-blocking language, it's likely that a request to a 3rd party affiliate tracking system might return slower than the add-to-cart request, which could cause problems.

In order to work around this problem, FoxyCart supports pausing and resuming an event. To pause an event, for example, the preprocess event, you'd return “pause” (as a string) instead of true or false. Here's a heavily commented example of adding a product to the cart silently:

    fcc.events.cart.preprocess.add_pre(function(e, arr) {
        if (arr['cart'] != "view") {
            console.log("Preprocess - adding a product silently");
            var jsonString = "";
            jsonString = 'https://' + fcc.storedomain + '/cart?output=json&1:quantity=2&1:name=Add%20in%20preprocess&1:price=3.23&1:weight=5&1:code=pre1';
            $.getJSON(jsonString+'&callback=?' + fcc.session_get(), function(data) {
                console.log("And added.")
                console.info(this);
                FC.json = data;
                // fcc.cart_update();
                console.log('= = = = = = = = = = = = = = = = = = = = =');
                console.info(this);
                fcc.events.cart.preprocess.resume();
            });
            return "pause";
        } else {
            return true;
        }
    });

Notice the return “pause”;. That halts the further execution of the preprocess event. So how to resume? Notice the fcc.events.cart.preprocess.resume();. That's similar to calling fcc.events.cart.preprocess.execute();, but instead of starting at the beginning, it resumes from where it was last paused.

If you have any questions on any of this, please don't hesitate to post on our forum. We're happy to help.

Site Tools