In HTML, the ampersand character (“&”) declares the beginning of an entity reference (a special character). If you want one to appear in text on a web page you should use the encoded named entity “&”—more technical mumbo-jumbo at w3c.org. While most web browsers will let you get away without encoding them, stuff can get dicey in weird edge cases and fail completely in XML.

This seems like a simple rule, but what about urls in HTML, javascript files, javascript in HTML, etc… Here’s a little guide to help clear that up:

Text in HTML:

<p>Jack &amp; Jill ran up the hill.</p>

A link in HTML (or any HTML attribute value):

<a href="http://lmgtfy.com/?l=1&amp;q=rick+roll">tired meme</a>

A link in javascript:

window.location = 'http://lmgtfy.com/?l=1&q=rick+roll';

If you’re using a web framework that escapes variables for you and you pass in a url as a variable into javascript, then you’ll have to make sure it doesn’t encode the ampersands. In Django, you would write something like this: window.location = '{{ url|escapejs }}';

Also, if this is inline javascript—in an HTML document, not a separate .js file—then you still shouldn’t escape the ampersand, which means the document will not validate as XHTML. Either throw it into a separate .js file or stop worrying so much about validating your code.

Inside an onclick in HTML:

<a href="#" onclick="window.location='?l=1&amp;q=rick+roll';return false">
    kablammo!
</a>

This is redundant to the second example, but worth pointing out since it’s javascript inside an attribute of an HTML tag.

Dynamically in Javascript (example using jQuery):

$('#result').text('Jack & Jill'); // .text() escapes the text for you
$('#result').html('Jack &amp; Jill'); // .html() sets the HTML directly
document.getElementById('result').innerHTML = 'Jack &amp; Jill';

In a Tweet

When to use&and when to use&amp;amp;http://bit.ly/dtiumF

Twitter auto-converts encoded ampersands…

Some extra notes:

  • If you want to use an ampersand as a value inside the query string of a url (and not as a delimiter for separating arguments), then you should use the URL-encoded value: %26
  • Quotes should be encoded too (&quot;), but I prefer to use utf8 curly quotes
  • The other main characters to remember to encode are < (&lt;) and > (&gt;), you don’t want to confuse your browser about where HTML tags start and end

The Google Analytics asynchronous tracking code came out of beta two weeks ago, and given my prior post on how scripts block page loads, I figured I’d briefly point out some interesting aspects of how the new tracking code works. The two things that I find interesting are (1) the asynchronous script loading and (2) the new syntax related to queuing events.


Which browsers support the async script attribute?

Here is the code that Google asks you to include, notice the “ga.async = true;” part:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXX-X']);
_gaq.push(['_trackPageview']);
(function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript';
    ga.async = true;
    ga.src = ('https:'   == document.location.protocol ? 'https://ssl'   : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

It appears that setting the “async” attribute to true makes the magic happen, but if you look into which browsers currently support the async attribute, you’ll discover that it’s only Firefox 3.6+. So what gives?

It turns out that if you insert a script—that you created using document.createElement—dynamically into a page, then it will be asynchronous in most browsers. I ran some tests when this code was first released, and my results are included below.

Note: this table describes for each browser whether the the domContentLoaded event waits for an “async script” to finish before triggering, or if it goes ahead and triggers while the script is still loading. It does the same for window.load and also shows if a script that appears lower on the page will wait for an “async script” to load before executing or if it just goes ahead.

domContentLoaded event (jQuery) window.load event Execution of lower script on page
Mac:
Safari 4.0.4 goes waits goes
FF 3.5.7 waits waits waits
FF 3.6 goes waits goes
Opera 10.10 waits waits waits
Chrome goes waits goes
 
Windows:
IE6 goes goes goes
IE7 goes goes goes
IE8 goes goes goes
FF2 goes waits waits
FF3.6 goes waits goes
Chrome goes waits goes

As you can see, the most important actions—the domContentLoaded event firing and a lower script executing—can both happen before the “async script” finishes loading for all of these browsers except for Opera and Firefox less than 3.6. It’s mostly asynchronous… mostly.


The asynchronous syntax: _gaq.push()

There’s a new syntax for tracking events, and also for setting the initial variables (like your account id) which looks like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXX-X']);
_gaq.push(['_trackPageview']);

and:

<a href="#" onClick="_gaq.push(['_trackEvent', 'Videos', 'Play', 'How is babby formed?']);">Play</a>

The magic happens when the script actually loads and then replaces the _gaq array with a new object that immediately executes all previously queued events and has a “push” method that will also immediately execute any event whenever it is called. The code for the new _gaq object looks something like this (a little simplified):

var GoogleAnalyticsQueue = function () {

    this.push = function () {
        for (var i = 0; i < arguments.length; i++) try {
            if (typeof arguments[i] === "function") arguments[i]();
            else {
                // get tracker function from arguments[i][0]
                // get tracker function arguments from arguments[i].slice(1)
                // call it!  trackers[arguments[i][0]].apply(trackers, arguments[i].slice(1));
            }
        } catch (e) {}
    }

    // more code here…
};

// get the existing _gaq array
var _old_gaq = window._gaq;

// create a new _gaq object
window._gaq = new GoogleAnalyticsQueue();

// execute all of the queued up events - apply() turns the array entries into individual arguments
window._gaq.push.apply(window._gaq, _old_gaq);

It’s a pretty cool idea that should make Computer Science professors who love interfaces really happy. If you want to read some more about the asynchronous tracking code, Mathias Bynens wrote a great post describing how to optimize the asynchronous Google Analytics snippet—it has some real passion for minimizing bits.

Extra: the “apply” method

If you’re not familiar with the “apply” method, it can be called on any function and takes two arguments: (1) an object that should be treated as the this object inside the function and (2) an array that will be the arguments of the function. It’s being used in the above examples to convert arrays into the arguments of a function (almost like unpacking in Python, but not as elegant).

Also, if you want to use the “apply” method purely to set the this object inside a function, you should consider using “call” instead, which is slightly faster, but requires you to pass the arguments in directly (not in an array).

my_func.apply(this, ['foo', 'bar']);
my_func.call(this, 'foo', 'bar');
This post has a brief explanation of Google Chart Tools and the chart builder called "Chart Maker". It also includes a chart that resembles Pacman—inspired by an existing popular image. read full post…
This post takes a look at another blog post on iPhone and PC game piracy to also point out how small a part of the market is actually buying games. read full post…
This is a technical followup to a post on SEOmoz.org with a specific example on how to setup an automated link building tool that monitors a google alerts RSS feed using YQL and then checks those pages to see if they linked to the site you are monitoring. This post explains the python code in more detail and gives specifics on how to set it up with the google apps engine. read full post…

Peter Coles

Peter Coles

is a software engineer who lives in NYC, works at Hunch, and blogs here.
More about Peter »

@lethys · flickr
tumblr