Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2007-621
$eventId
ID of event: wwdc2007
$eventContentId
ID of session without event part: 621
$eventShortId
Shortened ID of event: wwdc07
$year
Year of session: 2007
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC07 • Session 621

Advanced Concepts in Using the Prototype JavaScript Framework

Content and Media • 57:00

Discover how Prototype extends built-in objects to make cross-browser JavaScript development easier. This session will show you how to manipulate and traverse the DOM, add custom behavior to page elements, deliver UI elements incrementally with Ajax, and extract common functionality into reusable components. Plus, get a first-hand look at techniques for integrating Prototype and WebKit into your Cocoa applications.

Speaker: Sam Stephenson

Unlisted on Apple Developer site

Transcript

This transcript has potential transcription errors. We are working on an improved version.

We're going to be talking about Advanced Concepts in Using the Prototype JavaScript frame work by none other than the absolute creator himself Sam Stephenson. It's a great pleasure having him here and we really appreciate him coming down from Chicago to be with us this evening and at this time I'd like to welcome up on stage Sam Stephenson developer for 37signals and the creator of Prototype. Thank you very much.

( Applause )

Hi I'm Sam and today I'm going to talk about prototype and prototype is an open source JavaScript frame work that was created a little over 2 years ago. It's available for free, licensed under the MIT license so you can do whatever you want with it and it's built on code that's extracted from real world applications that we build at 37 Signals and that team of core contributors builds in their own applications; so this is real code and our goal with prototype is provide a nicer environment for JavaScript development.

So we want to smooth out cross browser issues and provide some things we think JavaScript has left out and prototype is not a widget tool kit so by widgets I don't mean Dashboard widgets. You can certainly use prototype in your Dashboard widgets but it doesn't provide new form controls and things like that but rather we think that with judicious use of HTML and CSS that combined with prototype you can make these things much simpler than...you can make them simpler yourself rather than configuring someone else's prepacked widget.

So in this session I'm going to go over a couple of APIs; I'll talk about how prototype extends JavaScript to make it easier to use and likewise how it extends the DOM so you can call methods on don elements to manipulate your pages and finally I'll talk about how we put all this together and show one technique for delivering interface elements incrementally using AJAX in your web applications.

So, this is how prototype fits in with the world; it lives in the JavaScript interpreter obviously; it's a single file so you just include with a script tag in your web pages and there's several third party libraries that build on top of prototype; one of those is Scriptaculous, provides visual effects and there's many other libraries provide behavior and things like that and then you build your application on top of all those and the browsers we support in prototype officially are internet explorer 6 and above, Firefox, Safari, and Opera.

So just to get everybody on the same page I'd like to go over the JavaScript object model and I'm going to assume that you already have basic knowledge of Java script; you know what the different types are; you know how to create a 4 loop and things like that but I want to talk specifically about the object model so that you can understand where prototype is coming from.

So in JavaScript everything is an object; here we have an object literal and that's just a collection of key value pairs; so we name, Sam; age 23; location, Chicago and we can assign that to a variable so here we're calling that variable person...and JavaScript lets us access properties on an object by using the bracket notation; so here we're getting the name.

We can also assign the name using equal operator in conjunction with the bracket and we can get that back and you see the value has changed and likewise we can use the dot operator to access properties and said values; so these are 2 ways to do the same thing...and functions in JavaScript we can make a function called greet here that just returns a string, takes a single argument, a name, and returns a string using that name; so if we call that we get our string back that says, "Hello Sam" using person dot name, but functions are just values in JavaScript so instead of saying function greet we can make an anonymous function and assign that to a variable in JavaScript; so this code is exactly the same as what we saw before; we're just assigning it to a variable explicitly instead of using the sugar that JavaScript provides...and we can make methods in JavaScript by assigning functions to properties of an object; so here instead of making a variable called greet we're assigning this function to the property greet of the person object and then when we call that function on the person object the value this inside of the function refers to that person object. So here we don't have to pass any arguments to the function, we're just calling this dot name.

And JavaScript provides ways to make object constructors using functions; so here we've created a constructor for person objects that takes 3 arguments, we capitalize the name of this because that's a JavaScript convention and what we do in this constructor, what happens is if you use this in conjunction with the new operator as you can see highlighted what happens is that Java script creates a new object and then invokes this function with this value with that new object; so here we're assigning all of our properties from the constructor to the new object and also assigning a function inside of that constructor and you can see what we can do using that constructor...but this kind of sucks because we have to create this greet function every time we instantiate a new person.

So JavaScript provides a solution for that which is called the prototype property and every function has this prototype property and it serves as a template for instantiating new instances of this object. So we can assign the greet function or anything that's going to be the same in every new instance of the object to the prototype object and then we can instantiate new people from the person constructor without creating that function every time. So this is really key; this is how prototype builds on everything that's built into JavaScript and extends it, and I'd like to talk about some of the language extensions now that we provide.

So we add functions to all strings in JavaScript; some of those are matching. We can check to see if a sub string is included in the receiving string; similarly we can check to see if the string starts or ends with a given string; these are available to all strings if you're including prototype in your web page.

We can repeat a string any given number of times; we can chain these things so we can repeat a string and then truncate it; so here the string will be no longer than 15 characters. We can strip leading and trailing white space from a string. We can convert plain strings into HTML quoted strings and we can convert HTML quoted strings back into plain strings.

We can make replacements on strings; so here we're taking a regular expression as a first argument; this is called G sub and a lot of these functions that you see are inspired by the Ruby programming language. We at 37 Signals used Ruby to build all of our applications and prototype was built to sort of mirror that to provide...to lower the impedance of switching between languages.

So G sub is a function that Ruby provides; we've copied that end prototype and you can take a regular expression here; we're looking for ING and we're just going to replace it with an empty string or we can get slightly more complicated; we can capture all vowels followed by 2 non vowel characters and we can swap their order in a string. The second argument to this call is prototype template and we'll talk about that in a little bit but here we're just swapping the order of these 2.

And G sub also takes an anonymous function for generating replacements; so here we get the match data passed back to the anonymous function and we can do stuff like check to see if the match is and, turn that into an ampersand or otherwise we'll just capitalize the word.

( Pause )

And prototype provides lots of functions for working with arrays also. Some of those are navigation; I don't know if you're like me but you can access array indexes by using the array bracket operators obviously so you could write 1, 2, 3 bracket zero to get the first element but I don't like these constancy in my code; I like more expressive code, so prototype provides first and last for getting at those very common elements of an array.

It also provides index of which is implemented in JavaScript 1.6 but not by every browser; only in Firefox, I think and maybe Web Kit. So prototype provides this for all browsers; you can get the index of any element in an array, shocking that that was left out, I know, but...we can also transform arrays.

So here we have nested arrays, if we call flatten; we get a flat array back. If we have an array that has nulls or un-defines in it we can call compact on it and get a copy of the array with those removed and there's a without function that will return a copy of the array without the value passed to it.

There's a unique function which returns all the unique values from the array and finally prototype provides lots of shortcuts for working with arrays. So here we have this greet function that we looked at earlier and JavaScript gives you an object called arguments and inside of each function and the arguments is just sort of like an array that gives you access to all the arguments you called the function with.

So we have this code, we want to get the first argument or we want to call some other method that prototype adds to arrays on the arguments array. If we try to run this we get a type error because arguments is not actually an array in JavaScript and there's several objects like this; one is node list. If you were to get elements by tag name from the dot you'll get back something that acts just like an array except it's not really. So all these methods that prototype adds to arrays aren't available to things like arguments and node list.

So to deal with that prototype provides dollar A and you just wrap your array like thing, that is anything that has a length property and can be accessed by index and it returns a copy of it as a real array; so here we can call first on it; it's now a real array.

There's also dollar W which is inspired by Ruby and Pearls percent sign W operator; basically just takes a string and splits it on white space so it's an easy way to create an array of words and as you can see you can call all the prototype methods on those arrays that are returned because they are real arrays...and prototype provides some object introspection methods; so a few of those are inspect which returns a JavaScript string representation of an object; keys which returns an array of all the property names of an object and values which returns the corresponding values of those keys as an array.

There's also some methods for composing objects. Object that extend is probably the most used; it's used heavily in prototype internally and what it does is copy all of the keys and values from the second object into the first object. So here we have an object name, Sam; age 22; we have a second object age 23; so you can see it has 2 properties that are identically named and the values of the second object are copied into the first and overwrite those values.

And similarly there's blend which works like extend but it will not overwrite any properties that already exist in the original object and an important note is that these methods return the same object that you pass, the first object so it does modify that object; it doesn't return a copy of it.

And just as an example of how we use this in prototype internally we use it to add methods in bulk to things like array dot prototype so all those array methods you saw earlier are added using object dot extend. It provides a nice convenient way to do that.

( Pause )

So another module that prototype provides is inspired by Ruby is innumerable and with innumerable you have your class or your object constructor; you can mix an innumerable into the prototype and by implementing a single method you get an entire suite of iteration functions; so prototype adds this to a few classes already; one of those is array.

So all of these methods are available to arrays and we'll show you some examples of using these with arrays but you can mix them into your own objects. And here's the implementation of the single method that you have to implement in your own classes; it's underscore each and what this does is simply wraps a 4 loop; so it takes an anonymous function, it's called interrater here and invokes it for each element of the array.

So for these examples I'll use this variable called WWDC which is an array created using this dollar W syntax but it's an array of 4 words, Apple Worldwide Developers Conference. The keystone of innumerable is each and this is how you invoke each. You pass it in anonymous function and that function is invoked for each element of the innumerable; so here we would get 4 pop up dialogs saying each word in the innumerable; so we'd see Apple Worldwide Developers and Conference.

And this anonymous function also has an optional index parameter so if you want to get the index you can just add on a second parameter and then our alerts would say Apple, Zero, Worldwide One, and so on. And it also provides control flow mechanism so sometimes say we want to break out of a loop but we can't use the JavaScript break command inside of an anonymous function; so what we have to do here is throw a special exception prototype gives you; this object called dollar break and this will let you break out. So here we say if index is greater than 2 throw a break; so here we would only see the first 3 alerts and you can do this in any innumerable function not just each...but where the real power comes in is when you can transform arrays or innumerable.

So one way to do that is with Map and here in this case the anonymous function is just going to return the first character of each element in the innumerable and then we get back as a return value of Map an array of all those returned values; so here we get the first letter of each element or we can also do something like get the length of every word...and it turns out doing stuff like that, accessing a property for each element of an innumerable is pretty common; so prototype provides a shortcut for doing that, it's called pluck and pluck is just Map that accesses each elements property. So here we're getting the length of each element in a more convenient fashion. We don't have to create this anonymous function.

( Pause )

And we can also call methods on these so here we're truncating each element to a size of 4 and again like the pluck this is a pretty common thing to do on a collection of elements. So prototype gives you invoke and invoke takes a string which is the name of the method you want to call on each element and you can optionally pass any other arguments; you would pass to that method and you'll get the values back.

Innumerable lets you search through innumerable objects pretty easily; find will return the first value in an innumerable that matches or rather for which the anonymous function returns true. So the first word with length 10 in this example is developers and we can use find all to get all of those matching the given condition.

So all of the words of lengths 10 returns an array developers and conference and we can also use grep to take an irregular expression and find all elements that match that regular expression. So here anything with an L followed by a vowel...that would be Apple and Developers. Finally there's max and min; so you return some value, some computed value in your anonymous function and prototype gets you the max or the min value.

( Pause )

There's some functions for matching elements in innumerables so if you want to check to see if an array or any innumerable includes certain element pass it to include and you get true or false back.

( Pause )

We can also check to see whether all elements match a certain condition; so if we want to see if all elements are longer than 4 characters, that's true but if we check to see if all elements are longer than 5 characters, that's false and similarly there's any which returns true if any of the elements match the given condition.

So here there is an element to match in which the first character is a W but there's not an element in which the first character is an X. There's some sorting capabilities built into innumerable so you can sort by a given anonymous call back here so we're looking for, in this case, we want to sort by word length; turns out the elements are already sorted by word length here but we can flip that around and sort by the inverse word length and we'll get our elements back in reverse order...or we can do something silly like pass map dot random as the interrater and get the elements back in random order.

You can compose things very easily using innumerable so the zip method in innumerable takes 2 innumerables and combines them. So here we're going to pluck the length of each element of the innumerable; we've got 1 array for that so that's 5, 9, 10, 10 and then we're going to take that and zip it back into the original innumerable; so now we have a new array returned in which each element is an array containing the original value and the length of that value.

And there's inject which is sort of like the Swiss army knife of innumerable. It takes an initial value, in this case we're passing zero and then that value is passed, the anonymous function is invoked for each element of the innumerable and sum here will start out as zero and then for each successive invocation of the anonymous function will be the return value, the previous invocation. So here we're accumulating a value; we're summing up the lengths of all the words and we get 34. You can do lots of stuff with inject; this is just a simple example.

So you get all this stuff for free if you implement a single method and we saw arrays implementation was 2 lines but you can do this in your own classes and get all this stuff for free and one such case of doing that is prototypes object range internally.

So object range lets you specify a start and end value and it'll give you an innumerable that lets you access all the values in between. So here we're saying new object range from 1 to 10 and then we're going to convert it to array and 2 arrays provided by innumerable.

So we get an array of all the values from 1 to 10...and we can also just call inject on that without converting it to an array first. So here we're summing up all the values from 1 to 100...we can also use it with strings, so here we're getting every letter from A to Z. You can implement yourself in your own types just a single method again that returns the next value and you can use your own objects with object range...and the preferred way to use object range is with dollar R because it's much shorter. So here this is the same thing as saying new object range but we're just saying dollar R one ten and here we're mapping each value in the range to that number of asterisks.

And prototype provides a simple way of doing string interpolation with the template object. So here we're creating a new template, we pass it a string and we've got these funny little hash brace things and inside of those we put a name; name, age, and location in this case and these refer to properties that are going to be substituted back into the string when evaluated.

So we can use it like this. We create a template and then we call evaluate on it and we can pass it any object; we can pass it an object literal if we want, such as we're doing in this case and then we get a string back with those values substituted in...and we can call the same template object on any number of objects.

So here we're using a different object literal and we're getting a different value back...and finally prototype provides a little wrapper around the constructor pattern we saw earlier and it looks like this; it's called class dot create and basically let's you move your constructor behavior into the constructors prototype.

So you can move all that behavior into a function called initialize and then what class dot create does is returns a new function that when instantiated with a new operator calls that objects initialized method; so it's just a, again, just a way to lower impedence when you're switching back and forth between languages like we often do in web programming. It's not intended to be a full implementation of class based programming but it's a very simple way to...not have to think about what you're doing to much.

So now I want to talk about how prototype extends a DOM We just talked about how it extends JavaScript itself and we what we do in JavaScript most of the time is work with DOMe elements so it's nice to add lots of things that we feel that DOM left out and that's what prototype does.

So the W3C DOM level 2 HTML specification defines all of these different objects for referring to the different tags in HTML and in a perfect world it would be really, really nice if we could just take these objects, access their prototype property and add methods to them but unfortunately it's not a perfect world. We have to deal with internet explorer.

( Laughter )

So as you can see here internet explorer doesn't let us modify these at all; it doesn't even give us access to them. Opera gives us access to HTML element dot prototype so we can add methods to all elements but we can't add methods to individual tags.

So we can't say like, "I want a method on a P tag or a form tag." Firefox does give us access to everything. Safari that ships with Tiger only gives us access to all elements; so it's better than nothing but it could be better; fortunately it's fixed in Leopard. Safari 3, Web Kit we have access to prototypes of all the individual tags.

So prototypes solution to this problem of not being able to add methods by default is to introduce the idea of the extended element and here's an example of how we might do that. You'd call document dot get element by ID to get some DOM element and we want to call it prototype method on it but if we're using internet explorer we would get a type error because that method won't exist.

So we can call element dot extend on that element and then if we try to call that method we'll get a value back and what element dot extend does is similar to object dot extend. It'll copy all of the methods that prototype catalogs internally for these objects and return the element extended.

Now if you're only developing for Firefox and Safari 3 you don't have to worry about this stuff. All elements are automatically extended for you but...most of the time you need a cross browser solution; so what you do in this case is make sure every DOM element you use in prototype passes through prototype somehow, passes through one of our query functions and you'll always get an extended element back from prototype.

So you never need to call element extend yourself basically. So, one of the keystones of prototype itself is the dollar function and this let's us...this is a shortcut for get element by ID essentially but again it always returns an extended element. So here we're getting, we can see this DOM tree on the left; here we're getting the DIV with ID article 4 or the element with ID comment 1...but the really nice thing about dollar is that you can pass it a DOM object as well.

So if you don't know what, if you want to write functions that take either a string or a DOM object all you need to do is call dollar on that argument and it doesn't matter whether someone passes a DOM element or a string you'll always get an element back.

We can also query by CSS3 selector and to do that we use dollar, dollar. So dollar is for a single element and dollar, dollar is for multiple elements. So a simple CSS selector would just be a tag name, in this case dollar, dollar, DIV will give us all the DIV tags or DIV dot content will get those with class name content.

We can also do some advanced queries like finding all DIVs with class name comment who have an immediate child that's an age 3 with class name author or something like this where we say, "All P tags that are the second child of the parent element," there's only one of those here and these work in all browsers.

So IE barely supports CSS1 but you can use CSS3 selectors anywhere you can run prototype and in Firefox, Opera, and Web Kit these CSS3 selectors are compiled into X path expressions; so they're really, really fast, especially in Web Kit; they're incredibly fast...but sometimes that's not enough. Sometimes we have a reference to an element but we want to get another element in relation to that element; so to do that prototype provides a whole suite of functions, again; one of those is down.

If you call down with no arguments you get the first child of the function and if you've ever programmed a DOM before you know you get these things called text nodes, if you use the built in DOM manipulation functions and they're a pain in the ass. You usually never want text nodes, you just want the DOM elements. So prototype only gives you DOM elements. You don't have to worry about text nodes. So here you won't get a white space text node; you'll just get the first element, that's the child of the DIV with ID article 4.

Similarly there is up which returns a parent element and these also take CSS3 selectors; so you can say up body dot article to get the body if it has class name article and these are nice to use in conditionals; so if you want to say for instance "Am I on a page in which the body has class foo" and in this case it doesn't so it returns undefined. You can use this in a conditional because undefined works like false and any other value works like true or any DOM element works like true. So you could say "if comment one up body dot foo" and then do something based on that.

And we can combine dollar, dollar with innumerable to get some pretty powerful constructs; so here's one example of that. We're getting all DIV elements with class name content and then we're invoking previous on that so we're getting all the previous elements from DIVs with class name content or we can get all H2 elements and get all the next DIVs from those H2s.

There's functions for manipulating class names in prototype; so the DOM gives you a single string to work with but that really sucks when you have multiple class names on a single element. So prototype gives you functions for working with those and one of those is has class name which returns true or false based on whether or not an element has a given class name. You can add a class name; if that class name is already there it doesn't get repeated; so here we're adding a class name to this element.

We can toggle class names; so this element already has a class name content. If we call toggle on it with content that class name goes away; otherwise it's added and we can also remove class names explicitly. And I found that I don't want to give a number but a good bit of my DOM manipulation is simply adding and removing and checking to see whether or not elements have class names; so this is very powerful because you can move a lot of your logic into CSS just by doing this; so these are nice tools to have. We can check to see whether or not elements are visible; this is done with the simple convention and that's whether or not the element has an inline style property; the inline display style property specifically.

So here we have this element and we want to see whether it's visible or not and it is because it doesn't have an inline style property. If we call hide on it prototype is going to set that inline style property so this is what the element would look like...and then if we call visible on that we get false back and we can also show it again and then that style property goes away.

There's also some functions for working with element attributes and read attribute is a wrapper around the DOMs built in get attribute function that works around some cross browser issues; again in IE which often returns utterly insane values for certain attributes but here we're just showing how you can read an attribute, get the value back.

You can also use these because these are real functions in IE again get attribute is not a real function so you can't use it in conjunction with invoke; it's some sort of native function; anyway you can use read attribute with invoke. So here we're getting all the A elements and getting their HREF values.

( Pause )

And this also works with XHTML bullion values so XHTML likes us to say disabled equals disabled. So prototype works with that; you can read attribute on some bullion and you'll get null back if it doesn't exist which would be like false in a conditional. If you use write attribute the corresponding function to set a bullion value we can pass true and you can see that's automatically converted into the right value for HTML. If we call read attribute on that again we get a string back and that string will evaluate to true; so you can again use these in conditionals very simply and again we can write values back; so if we write false for bullion that value just goes away.

There's some functions for working with elements styles and these will actually fall back to CSS. They'll read inline styles and styles that you set with CSS and a style sheet or a style tag; so here we've set font size on H2s and if we find an H2 called get style on that we get the right value back.

Similarly there's set style which takes an object collection of key value properties so we can set any number of styles all at once or we can just set a single one; here we're setting the width to 350 pixels...and finally there's some functions for working with DOM content and we like to do this with HTML.

So prototype lets you put HTML anywhere in the DOM, very easily, especially relative to given elements. So here we're going to find this H2 that says comment title and we're going to call update on it and what update does is replaces the elements in your HTML. So here we're just replacing that with a string fragment of HTML that inserts a span tag and you can see when this is called this is what happens.

( Pause )

You can also insert HTML...HTML fragments so here we have an A tag followed by a DR in a string and if we call insert on this element it's going to go at the bottom but we can also say that we want it to go at the top...or we can put it before or after an element and this is where before and after go and these all work with HTML...and finally we can replace elements outright. So instead of just replacing their content, we actually remove the element from the DOM and insert a new fragment of HTML generated from the string in place. So that's what that looks like...and we can also create elements very easily with prototype.

So we can use a new element constructor; we give it a tag name and we can optionally give it any attributes we want to set on that tag and then we can use real DOM elements with all of these functions we showed earlier. So here's an example of using it with insert instead of specifying a string we are just using real HTML, a real DOM element here...and there's the image.

Finally you can add your own methods to elements in prototype and it's very easy to do. So here's an example of adding 2 methods to all elements, dim and brighten, and these will just change the opacity and you can see an example of how you might call those in an element and you can also add methods to individual tags.

So here's an example of how we might a method called disable with to all input tags and you might call that something like this, get a form, go down and find the first submit button in that form and disable it with some string. So you can do this all yourself, add your own application specific methods and it's very simple to do.

So now I'm going to talk about how you can put all this stuff together and deliver your interface in your web application incrementally using AJAX...and this is just one technique for doing AJAX stuff. There's many, many techniques but this is a simple one that I found works really, really well because in my day to day work I really don't like to write JavaScript. I prefer to write Ruby. So I try to keep JavaScript as dumb as possible and fortunately our prototype helped me out with that.

So AJAX, the term stands for a synchronies JavaScript in XML and the XML presumably comes from the XML HTTP request object around which this is based but it's a pretty poor name because we can send any data along; it's just a wrap around each HTTP request. So prototype likes to think of this as a synchronies Java script end HTML and I'll explain what I mean in a little bit but first I'd like to show you how you can make a simple request in prototype; so we instantiate the AJAX dot request constructor, pass it a URL and you can pass it a set of options; so we can say, "I want this to go out as a get request." By default it's a post and you can say "When this request completes, say synchronies I want to just show a pop up dialog with the return value." So this is pretty basic stuff.

I'm not going to go over the whole AJAX request and update or APIs. There's a lot of stuff you can do but I want to focus specifically on what prototype provides which is automatic JavaScript evaluation and this is all provided if you use default options and configure your serve side language to deliver things in the proper way...and if you do that you can just make a simple AJAX request to a URL, that would look something like this, again using all of the default options and if your response has a content type of text/JavaScript and contains JavaScript code when that response comes back AJAX dot request will automatically evaluate that job de-script in that context of the window.

So this is powerful stuff; this lets us generate JavaScript programmatically; as you can see this stuff would be pretty easy to generate in any language; it's just...you know, you're working with elements and you're calling methods on them. Here we're removing class name; we're replacing an element in HTML with a string of HTML; we might use Scriptaculous to highlight that element and we can do any number of things...but sometimes you need to pass some data along with the request and to do that we need to serialize a form more often than not.

So you can do that with prototype pretty easily, make a new AJAX request and use a parameters option and then serialize some forms. So here we have a form with ID form and we're just going to call this serialize method on it and here's some sample data you might get back; it's just your in coded string and amazingly JavaScript doesn't provide a way to get that string from a form but prototype does and that's...that's okay but we can make this better. We can just fill this information into our form tag itself.

So if we have our form set up with an action, a method parameter, and an on submit handler we can just say that when this form is submitted we want it to go over AJAX and we do that by calling the request method on a form; this is added to all extended form elements in prototype and this is the same as the example we saw before...this, you can just write it like this, right in your form tag and this also lets you degrade gracefully; so if the user doesn't have Java script enabled this is just going to go out as a regular HTTP request, a page load rather.

So, in the past...well let me just say that when we're creating interface elements on the web typically we're going to have common operations and that's create, read, update, and destroy and there's HTTP verb equivalence of all of these methods; post, get, put, and delete but in the past we really haven't had access to those put and delete verbs and we've only been able to make post request by submitting forms but XML HTTP changes that; prototype solves some cross browser compatibility issues with that also but now what it amounts to is we have acces to all these verbs and so we can use these in our application to simplify our code.

So I'm going to talk about a specific interface element; this one is from an application we released a few months ago at 37 Signals called High Rise which is a shared contact manager and the element that I'm going to talk about is the task widget, so to speak, and this is what the default view looks like; this is in the side bar of every page in High Rise and you can click this button and get a nice little form here for adding task...and one way we could write this is by writing a whole lot of JavaScript for each of the different states of the form building these elements by creating the DOM elements internally with a bunch of JavaScript but really we have to render this stuff anyway as HTML because they're showing up on page loads.

So we already have this server side code that generates the form and we don't really want to duplicate this stuff; so prototype is a strong adherent to the dry mantra, don't repeat yourself, and one of those ways is by embracing enter HTML, the update method that you saw earlier that prototype provides and what we do is we, at least in Rales, an easy way to generate all this stuff on the server side using partials and partials are like little pieces of HTML and the entire application is built around using these partials. So we can send these down the wire over XML HTTP request and in conjunction with the 4 ACTP verbs we get a restful approach to creating interface elements. So I'm just going to show you sort of how we put that together.

So there's many different states of this control; one of them is, well you can set a time, so when we click this set a time link what happens internally, this is all very dumb JavaScript; we're just setting the value of a hidden field and then we're making an XML HTTP request and this is going to post to task/new and you can think of this as a resource.

So you might want to think of this a blank sheet of paper or a form that's printed out on a piece of paper and we're going to post some data back to that and we're going to say, "Let's change your state." So what happens is we get some JavaScript back; it's got the content type of text/JavaScript and it's going to re-render the form and that's it; that's all you have to do in the JavaScript side. The JavaScript is just serving as glue to put all this stuff together. So here we've added, we've set this hidden form value and now the Ruby knows to generate...a little time widget.

Similarly we can change when this task is due; as soon as we make a change to this select element, we post again to task/new and we get a little calendar back; so we're changing the states. We don't have any JavaScript here that renders a calendar; this is all done on the server side and it's very, very simple to do in Ruby and you're probably more comfortable with doing this on your own server side languages rather than writing JavaScript. So we think this is a good way to do it.

The HTML coming back down, the form gets re-rendered and whenever you click on...well when we change months, for example, we're just going to make another request; this is setting a form value, re-serializing the form, making that an XML HTTP request and we get the next month back...and if we click on any of those dates, what we're going to do is set it a hidden field and we'll talk about that in a second but let's go back and look at how this looks when we actually add a task.

So if we type something into this description field here and we click the add task button we're going to make a post to task; now here we're posting to a different resource because we're not just re-generating the form; we're actually submitting this and saying, "I want you to go in and create a new task." So our resource here is a collection of all tasks.

The verb is post and what we're doing is saying, "Take this data that we're serializing from this form, post it to this resource, and give me a new task back" and on our server side we take that and we just close the form, we send some JavaScript back down the wire to close the form, essentially hiding it, and re-rendering this containing element to show the new tasks and again we have to do this on every page load because these task are shown on each page.

So we already have Ruby code for generating this list of tasks in HTML and we don't want to duplicate it; so by using enter HTML, by using prototypes update method and combining that with a restful approach we make it really, really simple to only write your code once.

If we mouse over this element...we get this little nub end on the left and this gives us a delete and a change link and the way this works is by a little bit of JavaScript that looks to see what element you're mousing over and adds a class name to it and then this nubiness is always visible in the HTML but we use CSS to hide or show it. So there's an example of how you can use the add, remove class name stuff in prototype to really simply modify your page and separate your behavior into CSS.

So if we were to click the delete link you would actually make and XML HTTP request using the delete verb to the resource that we just added here and the URL to that resource would be task/4. Four is just some ID but it's a unique URL representing that single task; I'm not actually going to delete it. I'm going to show you what it looks like when you go to edit a task.

So if we click on this change link we're going to make a get request because we're not modifying anything here; we just want to get a resource and that resource is the edit screen. You can think of it as a screen or form or piece of paper or whatever but it's a resource belonging to that single task and when we do that we add a class name right after we make the request to the containing element called busy and that shows a little throbber so we get a progress indicator; we do this on all AJAX request actually but I'm just showing you here, showing another example of how you can use class names to separate out behavior like that; so we're showing a throbber and when that response comes back we get our form rendered again; again this is all rendered with Ruby, inserted right into the DOM using prototypes update method and this is our edit resource and it looks like the form we saw earlier except we're going to be changing existing object.

So we can change the due date again; if we do that we're making a post to...we're posting back to the same edit screen so we're not posting like we did before to the new tasks resource; we're posting to the edit resource...we get a calendar...and if we click on a specific date, this is setting a hidden field in the form and then if we were to submit that form it's going to serialize all the values of the form including that hidden field and the date changes and then it's reinserted into the DOM; this is all re-rendered again using that code we've already written on the server side. So the JavaScript again is very, very dumb. All it's doing is gluing this stuff together and it makes it really, really easy to write this stuff.

Finally let's look at what happens when you complete a task. Well we just have a little form in there and actually we don't have a form; we're just passing a parameter along; so we pass a parameter along with our AJAX request that tells it the task is completed; we add a class name, busy, and again we're re-using that class name that we used to show the throbber earlier but this time we're just going to show it struck out and then the response comes back and after 5 seconds that element is faded out.

So that's an example of how you can use all this stuff in your applications; again there's many ways to do it but I find the enter HTML method is a simple way to reuse code and to not have to think much about JavaScript at all and you can find all this stuff and more documented on the prototype web site at prototypejs.org.