Crazy Hijax!

Clean up your code with smatterings of AJAX

Myles Eftos

MadPilot Productions

The holy trinity

…or the three stooges of web design

The three stooges of Web design
Hijax is about linking HTML and JavaScript

Keeping HTML & CSS a part is easy

Moe from the three stooges Curly from the three stooges

So, you want to change the font size of text in a paragraph?

Enter the selector

HTML allows us to apply IDs and class names to tags — and using CSS selectors allows us to manipulate them

<div id="container"> <p id="content" class="content"> Piofect! </div> </div> #container p.content { font-face: bold; }

What about JavaScript?

Larry from the three stooges

We want to avoid this — it makes our html pages bigger, and it is ugly

<a href="hello_world.html" onclick="alert('Hello World!'); return false;">Say Hello</a>

We want this:

<a href="hello_world.html">Say Hello</a>

Let's revisit how CSS accomplishes this:

  1. Include an external CSS file
  2. Set the styles using selectors

The script tag lets us include a remote JS file, so we are half way there…

DOM the Christmas Donkey

Method #1 — DOM

HTMLCSSJavaScript
<div>Content</div> div { color: #00F; } document.getElementsByTagName('div');
<div id="myDiv">Content</div> #myDiv { color: #00F; } document.getElementById('myDiv');
<div class="myDiv">Content</div> div.myDiv { color: #00F; } document.getElementsByClassName('myDiv');*
* This method doesn't exist in HTML4 but looks like it'll end up in HTML5.

Some example goodness

This should add quotations around the text in all the blockquote tags

var blockquotes = document.getElementsByTagName('blockquote'); for(i = 0; i < blockquotes.length; i++) { var preQuote = document.createTextNode("&ldquo;"); var postQuote = document.createTextNode("&rdquo;"); blockquotes[i].insertBefore(preQuote, blockquotes[i].childNodes[0]); blockquotes[i].appendChild(postQuote); }

This set the class name of the paragraph with an id of “footer” to “green”

var p = document.getElementById('footer'); p.className = "green";

So slooooow

HTMLXPath
<div>Content</div> document.evaluate("//div", document, null, XPathResult.ANY_TYPE, null);
<div id="myDiv">Content</div> document.evaluate("//*[@id='myDiv']", document, null, XPathResult.ANY_TYPE, null);
<div class="myDiv">Content</div> document.evaluate("//div[contains(@class, 'myDiv')]", document, null, XPathResult.ANY_TYPE, null);

Note: All of these function return an Array, including the equivalent of document.getElementById()

Foiled by IE again! Almost…

var Selectors = { cache: {}, store: function(selector, element) { this.cache[selector].push(element); element.runtimeStyle.behavior = "none"; } } div.myDiv { behavior: expression(Selectors.store("div.myDiv", this)); }

This only works during the loading phase of the page

Hijax

function bind() { var element = document.getElementById('someAnchor'); element.onclick = function() { alert('Bound!'); } }

In a bind

Larry from the three stooges

IE Hack #2

// for Internet Explorer (using conditional comments) /*@cc_on @*/ /*@if (@_win32) document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>"); var script = document.getElementById("__ie_onload"); script.onreadystatechange = function() { if (this.readyState == "complete") { bind(); // call the onload handler } }; /*@end @*/

The defer function convieniently defers the execution of the supplied script until AFTER the DOM loads. Excellent!

Safari Hack #1

if (/WebKit/i.test(navigator.userAgent)) { // sniff var _timer = setInterval(function() { if (/loaded|complete/.test(document.readyState)) { clearInterval(_timer); bind(); // call the onload handler } }, 10); }

This one just checks for the status of the document.readyState flag every 10 ms. Not great but works.

You know what? There are libraries for these sorts of things, out very own Andrew Tetlaw has a fine example: FastInit.

So what can we do?

Make improvements

Speed stuff up

Things to watch for

It's not all clam chowder

Curly battling with clam chowder

The X Factor

Lies!

JSON and the argonauts

var json = { id: 8, title: 'Object number 8', body: 'This is a serialised version of a JavaScript object', childIDs: [4, 6, 4, 7] }; var instance = eval(json);

Some libraries

Behaviour

Allows you to reference nodes just like you would with CSS — via selectors.

var rules = { '#navigation li' : function(element) { element.onclick = function() { alert('You clicked me!'); } } }; Behaviour.register(rules);
  • Makes applying rules super simple
  • Avoids concretitis

Some libraries

Wrapper libraries

Try to fix the discrepencies in browser implentations

  • Prototype
  • JQuery
  • Mootools

Some libraries

Visual effects

Make is easy to create animations and effects, such as drop and drag

  • script.aculo.us (Prototype based)
  • Moo.fx (Prototype or Mootools based)

window.unload = conclusion

Have you been paying attention?

  • Browser support sucks (CSS all over again)
  • Reusability
  • Cleaner markup

References

  1. Behavioural Separation — Jeremy Keith
  2. Executing JavaScript on page load — Simon Willison
  3. Prototype JavaScript library — Sam Stephenson
  4. Mootools — Valerio Proietti
  5. Behaviour — Ben Nolan
  6. script.aculo.us — Thomas Fuchs
  7. The window.onload Problem - Solved! — Dean Edwards
  8. Yet Another JavaScript Library Without Documentation — Dean Edwards

Questions

Erm, questions?