Oh, behave! An example of Jquery with Low Pro behaviors.
I'm going to do a quick tour of the javascript code used in the upcoming design of alonetone, the kick-ass home for musicians.
For this version of alonetone, I ported the existing code to jquery to try out the library. As a low pro addict, however, I wanted to use the behaviors I know and love. Luckily, just about this time, a port of low pro to jquery was written by the trusty and talented Dan Webb.
Why low pro, when jquery is already unobtrusive?
- Behaviors allow me to easily name and encapsulate functionality that I can later reuse.
- Behaviors are inheritable, allowing me to group like things together, and avoiding writing chunks of similar code.
- Low Pro's implementation of behaviors has Event Delegation built in, vital for larger web apps (unless you want browsers to try and cope with 400 event bindings).
- I like the way behaviors look and way they read. My code feels more organized. I can quickly tell what is going on. I write less, and more importantly, I write less mess.
A quick note on this implementation
I have a github fork of low pro for jquery that contains a fix I needed for event delegation, as well as a (rudimentary) implementation of automatically binding ajax callbacks (in Remote.Base ported from the Prototype version). You'll need to use my fork, until Dan Webb pulls from it or otherwise adds the ajax callback bindings.
What we want to build
In this example, we are building a comment form that submits in-place via ajax. We've got a couple specific requirements.
- When a user clicks submit, we want to disable the submit button and change the text to "submitting..."
- We also want to show a fancy ajax spinner to reinforce the 'hold on, something is happening'
- If the comment submits successfully, we want to display a success message and clear the forms contents, allowing it to be submitted again.
- If the comment submit fails, we want to display a "Sorry, that didn't work!" message and keep the form contents in case the user wants to submit again.
- Either way, after the request comes back, we want to stop the spinner, and re-enable the submit button with the original button's text.
Complex? Nah.
For a demo of this, you can check out alonetone's staging site and either "report something" or play a track on the site (the comment box will open for you). Go ahead, don't be shy.
The code, with comments
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
// First off, we want to take advantage of Remote.Form // We are going to inherit from that existing behavior // which comes built in with low-pro CommentForm = $.klass(Remote.Form, { // When inheriting from an existing behavior // we can use the special variable called $super, // which gives us a reference to the behavior's parent. // You can use $super anywhere a parent already defines // a function. // In this case, we are inheriting from Remote.Form // which in turn inherits from Remote.Base. // We want to make sure the initialize function // in Remote.Base gets called, as it automagically binds // our ajax callbacks initialize : function($super,options) { // initialize is called when you first attach a behavior // to an element or a group of elements. // A common pattern is to define some variables here // to be used in other actions/methods of the behavior // Our submit button this.submitButton = $('.comment_submit', this.element); // Our submit button's original text this.submitText = this.submitButton.val(); // The "loading" spinner this.spinner = $('.small_spinner',this.element); // The box that contains our result message this.resultBox = $('.comment_waiting', this.element); // The text area we want to clear on success this.textarea = $('textarea', this.element); // E.T. phone home $super(); }, // You may be wondering where the onclick handler is... // It is already defined for us in Remote.Form // The next 4 functions are automagically bound // to the ajax call that Remote.Form makes // before sending, show the spinner and disable the form beforeSend:function(){ this.spinner.show(); this.disable(); }, // after sending, hide the spinner and enable the form complete:function(){ this.spinner.hide(); this.enable(); }, // on success, fill our result box with some 'feel good' text success:function(){ this.resultBox.text('Submitted, thanks!').fadeIn(100); this.textarea.val(''); }, // on error, fill our result box with an error message error: function(){ this.resultBox.text("Didn't work. Try again?").fadeIn(100); }, // These two functions disable/enable the form and toggle // the text of the submit button disable:function(){ this.submitButton.attr('disabled','disabled'). val('sending comment...'); }, enable:function(){ this.submitButton.removeAttr('disabled'). val(this.submitText); } }); |
Attach the behavior and you are done
So, the point of writing that behavior was to have an encapsulated idea of what my version of a Comment Form looks like. Now, I can go ahead and attach the behavior to an element or group of elements of my choice, either on dom load....
1 2 3 4 5 |
jQuery(function($) { // Find all of my comment forms and give them my behavior $('div.comment_form form').attach(CommentForm); }); |
...or attach it within another behavior (as I do on alonetone)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Track = $.klass({
// ...my track implementation...
// I want to create the CommentForm behavior on the fly.
// I'm going to call this function somewhere else in the Track Behavior
openCommentForm : function(){
// I use .attachAndReturn() because I want this.commentForm
// to refer directly to this instance so I can "talk to it" later.
// Also, notice that attachAndReturn is handing me back an array
this.commentForm = $('.comment_form form',this).attachAndReturn(CommentForm)[0];
}
});
|
For more...
I may write a bit more about behaviors, but until then, you can check out alonetone's github repo for more examples. It's not always pristine and pretty (it drives a production site), but have fun!