Monday, October 08, 2012

Adding jQuery Deferred Support to AmplifyJS Request

A common feature request in the AmplifyJS Google Group is for the request component to support jQuery Deferreds.

For a brief overview of the request component you can check out a post I recently titled Mocking jQuery AJAX with AmplifyJS Request. In addition there are many more features listed in the official documentation.

A Little History of the Library


Before I address that request, let me go into a little history about the AmplifyJS library. When AmplifyJS was announced there was a conscious decision to not have a hard dependency on jQuery and to make it library agnostic so that you could use Dojo, MooTools, YUI, or something else. So, the publish/subscribe and store components do not use jQuery at all. The default request type shipped with AmplifyJS does utilize jQuery AJAX, but you can just as easily create a new request type that uses Dojo, MooTools, etc.

3 Ways to Provide jQuery Deferred Support


Now that we have some of the history out of the way, let's get back to the feature request. Adding a tight dependency to jQuery's Deferreds implementation isn't in the AmplifyJS roadmap since it was written to be library agnostic. You can however, write your code such that the request component plays well with jQuery Deferreds if you so choose.

1. Manually Wiring Up Deferreds


Back in October 2011 Eric Strathmeyer (@strathmeyer) answered a Google Group post regarding adding jQuery Deferreds support to amplify.requst. On of his suggestions was to manually wire up the amplify.request with jQuery Deferreds for both the success and error callbacks as shown below.


2. Using a Helper Function


If you find yourself wanting to use jQuery Deferres often with amplify.request then you can use the following helper method that both Eric and Scott González (@scott_gonzalez) have recommended.


3. Using the amplify-request-deferred Plugin


I thought some developers might want a syntax that looked more native when using jQuery Deferreds with amplify.request, so I went ahead and made the amplify-request-deferred plugin, base on the above work by Eric and Scott. To get started all you have to do is to include the plugin immediately after amplify.request.


Once you have the plugin included on your page, then you can use the plugin with syntax like the following...


Conclusion


Hopefully one of these solutions is sufficient for your needs. This is a very common request, but as I mentioned in the history section above the AmplifyJS library would rather be agnostic and not depend on any one library. I hope this is helpful to you. Thanks.

Wednesday, October 03, 2012

Mocking jQuery AJAX with AmplifyJS Request

In my opinion the most powerful part of the AmplifyJS library is the request component. The documentation is nice, but I wanted to highlight the mocking piece in particular because it is very powerful, but is easy to miss.

Being able to separate what a request looks like from the actual request itself proves to be a very effective way to develop. It protects yourself from future changes to the request/response handshake and also makes it really easy to mock responses for unit testing or for rapid prototypes.

Standard Request Define and Request Usage


The following snippet of code defines what a request should look like that communicates to twitter to get someone's recent tweets.


When you want to use the definition above you just reference the resourceId that you provided ("getTweets"), you pass any data you want to pass along, and give a callback function that will be invoked when the response comes back.


Easily Mocking the Request


If for some reason you don't have internet access, the service you are using is unstable, or you just need to unit test some code then you can mock the response by redefining the resourceId and using a function as the 2nd parameter that will be used for the mock.


Using mockJSON to Generate Randomized Data


If you are anything like me, then you are awful at making sample data. I end up with something like "Test 1", "Test 2", etc... which is laborious, looks silly, and doesn't really exercise your UI at all. If you want to semi-randomize your data for prototyping then using the mockJSON library can be helpful. The following code says to generate an array of 20 to 30 tweets that follow the format specified.

The mockJSON library, written by Menno van Slooten (@mennovanslooten), I am using has been beneficial to me when building prototypes when the backend is either unstable or not developed yet.


The following screenshot is an example of what one of the above objects looks like after using mockJSON. As you can see, the object can almost pass as a legitimate tweet (minus the actual tweet.text). mockJSON allow you to create custom keywords to extend the native ones like @MALE_FIRST_NAME, so you could conceivably make a new keyword that can make a more believable tweet.text.


If you defined the same resourceId multiple times, then the last one defined wins. So, the following output is from the mocked version using mockJSON to semi-randomize the twitter response. Note: If I wanted to switch to the real twitter, I would just need to comment out my mocked versions.



I just scratched the surface of what you can do with AmplifyJS Request. It can support caching, decoders, dataMaps, custom request types, and more. Check out the documentation for more details.

Monday, October 01, 2012

Don't Initialize All the Things in jQuery.ready()

One of the first impressions a user gets is loading your web application for the first time. Users don't have a high tolerance when it comes to page speed. They want to see something almost immediately and then be able to start interacting with your web site shortly after.

If your website utilizes JavaScript and jQuery, which many web sites do, it is very tempting to pre-initialize all of your logic (plugins, widgets, modules, event handlers, etc) in order for them to respond as fast as possible. Unfortunately, initializing ALL THE THINGS during page load works against the user's goal of loading quickly. Instead of initializing everything when the page is ready you can instead wait to initialize portions of your application until they are needed.

The following examples will show two ways of initializing a date picker. The first way will "Initialize All the Things" and the other example will use the "Just-In-Time Initialize" principle.

Example Markup


In order to convey the idea I'm trying to explain it is probably easiest to show a code sample and then talk about what is happening. We will be using the following HTML for the markup that our code examples will be using.


I am using Twitter Bootstrap to made the UI look more presentable and that is why you are seeing some extra classes attached to the above markup.

The markup shows a simple form with various input elements. In the form we will have multiple date fields that we will want to initialize using the jQuery UI datepicker widget.

Initialize All the Things


The following jQuery code looks familiar to many snippets that you'll might find across the internet, in tutorials, and possibly in your web applications.


I am using the small moment.js library to help with data manipulation. It is a handy date library that I think you'll find very compelling and rich with features.

Let's unravel what the code is doing...

  1. We wait until the document is ready before running the rest of our code.
  2. Once the DOM is ready, then select all the input elements on the page with the date class.
  3. jQuery will implicitly iterate over it's internal collection of elements and initialize each one with the datapicker jQuery UI widget.

Pros of this Technique


  • When the user interacts with any of the input.date elements they will already be setup and therefore will respond extremely quick.

Cons of this Technique


  • Your code has to wait until the DOM is ready before it can select the elements. It would be nice if you could utilize the time between when jQuery is executed and when the DOM is ready.
  • The selector doesn't have any context so it is looking throughout the whole DOM looking for input elements with the date class. This would be considered a sub-optimal selector since there is no limit to the scope or context of what is being searched.
  • The code is initializing all the elements (implicit loop) whether you need them or not. Sure, the widgets are ready when you need them, but is all that up front code necessary?
  • There is quite a bit of extra code running that isn't necessary yet before the page has even fully loaded. The affects the overall User Experience of page load, which is very key concern to users.

Just-In-Time Initialize


The following code snippet looks considerably different from the previous example, but the end result is the same and the Pros and Cons are quite different. See if you can spot out the differences.

You can view, run, and edit the above code sample from JsFiddle or you can interact with the embedded version below.



I am using the toastr library to show messages indicating when the elements were initialized. This library was created by Hans Fjällemark and John Papa.

As we did in the previous example let's outline what is happening in the code and then we will examine the Pros and Cons of this technique.

  1. We immediately set up an event handler to wait for User Input before initializing the datepicker. This allows the code to run immediately after jQuery has been executed on the page before the DOM is even ready. We don't need the DOM to be ready because we are delegating our event to the document context.
  2. We aren't initializing all the input.date element, but are only listening to the focus event. This event will propagate (a.k.a. bubble) up the DOM tree until it gets to the document at which point jQuery will determine if the item focused on matches any of the metadata it has stored. This metadata match is surprisingly fast because it is only matching this "crazy" selector against the one DOM element that was focused on and not the whole DOM tree.
  3. Our advanced selector is looking for input.date element that doesn't have the hasDatepicker class. If this is a match then that one DOM element will be initialized. After that point, if the element is focused on later the selector will no longer be a match because jQuery added the hasDatepicker class during the it's widget creation.

Pros of this Technique


  • Very fast page load speed because you are only adding an event handler to the document with some metadata that will be used later
  • There is no jQuery selection being made on DOM ready
  • There is no implicit looping going on to initialize the elements
  • Only the elements that are about to be used are initialized so there is no wasteful code being executed
  • The focused elements are only initialized once
  • This technique will also work for dynamically added date pickers added to the DOM

Cons of this Technique


  • There is some overhead of the focus event having to propagate up to the document and having jQuery check the metadata to see if there are any matching selectors for the element in question, but this is mostly a wash since it is only testing one element.

Conclusion


You want to limit initializing all the things all the time. It can be helpful if you start to think about delaying initialization until the point when you need it or possibly right before. By doing so you can utilize the time right after jQuery is executed and not wait for DOM ready then you are able to use that precious time during page load. In addition you can have a crazy weird jQuery selector that still is fast. In our last code example above had a complicated selector, but it was very fast because it is only being tested against the one element that was focused on and not the whole DOM tree.

Much of this material was gleaned from an awesome series Doug Neiner has given at the past several jQuery Conferences entitled "Contextual jQuery" (video & slides). If you haven't already seen his talks or slides I highly encourage you to go through them.

Tuesday, September 25, 2012

Control the Complexity of Your JavaScript Functions with JSHint

New JSHint Features


Many of you are aware of the JSHint code quality tool that has been around for the past couple of years. As of recently, the following new options that have been added regarding the complexity of a function.

  • maxparams
  • maxdepth
  • maxstatements
  • maxcomplexity

Parameters, Depth, and Statements


By reducing the number of parameters, the number of nesting, and the number of statements in your function you can dramatically increate the readability and modularity of your code.

The following piece of code shows using the maxparams, maxdepth, and maxstatements to warn us of possible issue with our functions.



JSHint gives an error that too many parameters were used because we limited maxparams to 3 and the code accepted 4 parameters. An error occurred because the depth of logic is too deep because we limited it to a maxdepth of 2. We will also get an error about the number of lines in our function because we limited maxstatements to 5 and we have many more than that.

Cyclomatic Complexity


A less commonly known software metric used to evaluate functions is Cyclomatic Complexity. Like it sounds, it's purpose is to calculate the overall intricacy of a function and to give a score that reflects it's complexity.

"The cyclomatic complexity of a section of source code is the count of the number of linearly independent paths through the source code." --http://en.wikipedia.org/wiki/Cyclomatic_complexity

In addition to the above parameters, depth, and statement metrics you can now track the overall complexity using the maxcomplexity option.



As you see above, the above function has more complexity that what we set in maxcomplexity.

You might be wondering what a reasonable maxcomplexity value is for your project. In the 2nd edition of Steve McConnell's Code Complete he recommends that a cyclomatic complexity from 0 to 5 is typically fine, but you should be aware if the complexity starts to get in the 6 to 10 range. He further explains that anything over a complexity of 10 you should strongly consider refactoring your code.

Global Options


Instead of adding these options to the top of each and every JavaScript file you an instead use a .jshintrc file in your project and JSHint should pick up those settings. This is handy if your project is large and you want some consistent settings across the board.



Monday, September 10, 2012

Custom JSBin Code Editor Settings

You may already know about the JSBin tool created by Remy Sharp (@rem). It was the first website of it's kind that I'm aware of that lets you quickly prototype and play around with web concepts in a way that is social and fun. Although it has been around for a while Remy has been adding more and more features to it recently.

One of the ones that I want to point out is the ability to modify the settings of it's internal code editor in order to look and behave something like the following screenshot...


CodeKit Configuration Settings


JSBin internally uses the CodeMirror library for it's HTML, JavaScript, and CSS code editors. JSBin exposes the Configuration Settings of CodeMirror and allows you to set them yourself. The settings are stored in localStorage so they are available the next time you use JSBin. CodeMirror supports a whole suite of settings, but the following are the ones that I am most interested in:

  • theme - Color scheme that will be used for the editor.
    Currently the following themes exist: solarized-light, solarized-dark, monokai, vibrant-ink, cobalt, blackboard, ambiance, & jsbin (default)
  • indentUnit - The number of spaces inside a block of code
  • smartIndent - Automatically indent based on the context of what you are doing
  • tabSize - This defines the width of the tab character
  • indentWithTabs - Determines to use tabs instead of spaces when you intent
  • autoClearEmptyLines - Clears whitespace only lines when the cursor exits the line
  • lineWrapping - Wrap the contents of the line if it extends outside of the viewable area
  • lineNumbers - This will show lines numbers in the left gutter
  • matchBrackets - Matches associated bracket when your cursor is on a bracket

Making Changes to Your Editor Settings


You can set the above options manually in your browser's console like the following snippet of code...


Sharing Your Editor Settings With Others


If you want to share with others your settings for a specific JSBin you can add an api URL parameter pointing to a configuration file.

The following URL will load JSBin with a custom set of code editor options.

http://jsbin.com?api=http://j.mp/jsbin-settings

The http://j.mp/jsbin-settings file I am using looks like the following...


Remy has been making videos about various features of JSBin on his Tips and Bits blog. You can view the video about the above feature here...


Tuesday, July 24, 2012

Exterminate Common jQuery Bugs Video


I recently gave a presentation at aspConf: The Virtual ASP.NET Conference on `Exterminating Common jQuery Bugs`. I recorded the session locally and the aspConf guys graciously processed it and hosted it on the Channel 9 website.

The video above is the full 1 hour session with all of the points from my blog series plus a couple more that I haven't blogged yet. You can view the slides from the presentation from my GitHub account.

If you enjoy the talk please consider rating it on Channel 9 and SpeakerRate.

I presented this same talk at the jQuery San Fransisco 2012 Conference about a month ago, but I was limited to 30 minutes so I had to trim down what sections I covered.

The session is not referring to bugs in jQuery core itself, but rather bugs that tend to crop up in your application code the more you use jQuery.

Each point focuses on Examining a code sample with a bug, Explaining what is going on, Exterminating the bug by solving it one or more ways, and then dive into some Extra tidbits of knowledge that might be interesting about that topic.

The bugs vary from synchronous/asynchronous code, looking into the $.each method, looking at some confusing jQuery methods, digging into event delegation, unpacking strange animation behavior, and much more.

I hope you enjoy the session and pick up at least one thing you didn't know and can start using right away.

I want to thank all the staff and volunteers that put together and ran the jQuery and aspConf conferences. I had a blast participating in the events and enjoyed interacting with the audience in person and virtually. Thanks!

Tuesday, May 22, 2012

QUnit Composite Addon: Running Multiple jQuery Test Files

Introduction


When you start Unit Testing your application with QUnit you'll notice that you'll have lots of different QUnit files that thoroughly test one feature or component of your system.

Instead of opening each one of those test files and running them separately, wouldn't it be nice if you could launch one file that would run all the tests?

Thankfully, there is a addon for that and it's called the Composite addon!

Composite is a QUnit addon that, when handed an array of files, will open each of those files inside of an iframe, run the tests and display the results as a single suite of QUnit tests. -- https://github.com/jquery/qunit/.../addons/composite

Setup


Setting up the Composite addon is pretty easy. All you really need to do is to get the qunit-composite.js and qunit-composite.css files from the Composite Addon Repository in GitHub and then tell QUnit what test files are a part of your Test Suite! See the following for an example setup.


Running Example


I've taken the Unit Tests from a couple of blog posts I've done recently (filterByData jQuery Plugin: Select by HTML5 Data Attr Value & jQuery :dataAttr Pseudo Selector) and have decided to bundle them together using the QUnit Composite Addon.



NOTE: Normally your URLs will look much cleaner than these in this example. Since I'm running these tests in jsFiddle the resources are pointed to their jsFiddle hash appended with /show so that they will render only the result.

Running from the file:// Protocol


In order for this to work you must host your files in a web server because the Composite addon relies on making AJAX calls to pull in the other QUnit files. If you are trying to run the test from the file:// protocol then you will get an error and the tests will not run. If you want to run the tests from Google Chrome you can enable the allow-file-access-from-files command line parameters.

  • Mac: open /Applications/Google\ Chrome.app --args --allow-file-access-from-files
  • Windows: C:\path\to\chrome.exe --allow-file-access-from-files
  • Linux: /usr/bin/google-chrome --allow-file-access-from-files

Conclusion


Using the QUnit Composite addon is very handy to get a quick high level view of the health of your web application. There is some overhead when running all of the tests at one time, but by making it easier to run all of your tests makes the likelihood of you running them much higher than otherwise.

Wednesday, May 09, 2012

jQuery HTML5 :dataAttr Pseudo Selector

Problem


A while back someone on twitter was asking me how they might find a set of DOM elements by using doing a partial search on their HTML5 data attribute.

I'm not actually sure what type of use case you would need for such problem, but I thought it was an interesting issue to work on, so I went ahead and took a stab at solving it.


Desired Solution


In order to solve the above example of finding elements that start with a certain HTML5 data attribute, I wanted to follow a similar API to that of jQuery Attribute Selectors with the ^=, $=, etc... syntax. The following is an example of how I thought the solution should look like.


Custom Pseudo Selector


In order to create an API like the above I needed to create a custom pseudo selector, much like what you've seen when using :last, :odd, :eq( number ), and numerous other common selectors.


Unit Tests


I didn't want to just have some code laying around that wasn't thoroughly tested, so I went ahead and created a set of unit tests to cover various scenarios. I could have kept going, but I thought the following was a decent set of tests to start with.


Thursday, May 03, 2012

Tweet Package for Sublime Text 2

I was browsing through the list of available packages in Sublime Text 2 and noticed once entitled Sublime Tweet that caught my eye, so I thought I would try it out.



How to Install


With Package Control

The easiest way to install Sublime Tweet is using Sublime Package Control. If you don't already have Package Control installed, then I highly recommend it. It is a very easy way to find and manage packages.

  1. Open the Command Palette... Shift-Cmd-P
  2. Choose Package Control: Install Package
  3. Select Sublime Tweet from the List

Without Package Control

It isn't necessary to have Package Control to install Sublime Tweet. Instead you can clone the repository from GitHub into your Sublime Text 2 package directory. For detailed instructions on what path to use for your operating system please refer to the documentation on the Sublime Tweet repository on GitHub.

How to Setup


The first time you try to use Sublime Tweet it will ask for authentication information.

  1. Open the Command Palette... Shift-Cmd-P
  2. Choose Tweet
  3. A browser will open and Twitter will generate an authentication token for you
  4. Copy the authentication token and paste it into the prompt in Sublime Text
  5. Now you are all setup for using the package

How to Use


Sending a Tweet

  1. Open the Command Palette... Shift-Cmd-P
  2. Choose Tweet
  3. Type in your tweet and press enter

Reading Your Timelime

You can also read your timelime and favorite, reply, and open embedded URLs, but I'll refer you to the documentation on the Sublime Tweet repository on GitHub.

Friday, April 06, 2012

Interviewed on The Code Project's Coder Series


I was recently asked to participate in The Code Project's A Coder Interview series by Terrence Dorsey (@tpdorsey)

You can view the A Coder Interview With Elijah Manor from The Code Project website.

The questions that I answer in the interview are…

  • Who are you?
  • What do you do?
  • What is your development environment?
  • What new tools, languages or frameworks interest you?
  • What is your coding pet peeve?
  • How did you get started programming?
  • How has the developer community influenced your coding?
  • What advice would you offer to an up-and-coming programmer?

The following are some other notable interviews they have done recently...


Thank you Code Project and Terrence Dorsey for the honor of being included in your coder interview series.

Thursday, April 05, 2012

How a Programmer Lost 46 Pounds and Survived

So I started this journey 46 pounds ago on July 6th, 2011 weighing in at 196 pounds. That may not sound too bad, but keep in mind that I'm only 5' 6" tall!

It seems every year I've been gaining more and more weight. A combination of stress, overeating, late night snacking, and eating a bunch of unhealthy foods brought me to where I was. I used to hold back and resist getting larger pants, but it soon became ridiculous trying to fit into clothes that I really shouldn't be wearing. So, I eventually got up to a 36` waist so I could fit comfortably.

Near my heaviest weight an uncle of mine passed away from a heart attack. At the funeral I was approached by my sister and my aunt. They both showed concern for my condition. Deep down I knew I was at high risk for multiple health related problems, but having a relative die because of health issues opened my eyes.

So, what did I do to loose weight? Well, it mostly began when I started a special MetaGenics Ultraclear Detox diet in another attempt to reduce or eliminate chronic headaches. The passing of my uncle and other health problems (pain in my legs) were additional encouragement for me to continue with this detox, to start exercising, and to continue eating well.

The detox was a one month strict combination of reducing sugars, dairy, meat, carbs, and pretty much everything but vegetables, fruit, nuts, and brown rice. In addition I took a series of shakes and pills to attach and flush out any toxins that were in my body. After the month of this detox program my headaches were not any better, but physically I felt a lot better and I was loosing quite a bit of weight in the process.

I could not have stuck to this program without my wife. Having her support was vital for me completing this detox successfully. Our grocery list changed quite a bit and she helped prepare meals that we can both eat that are healthy and delicious.

The detox was not the only reason for my weight lose. I also was exercising quite regularly. I used to run outside, but that was too hard on my body. My shins would hurt, I'd get hot, and after about 15 minutes or so my arms would go numb! So, I was inspired by my 6yo daughter's swim lessons and decided to start swimming. As it turns out, swimming it is easy on my body and I stay pretty cool during the workout. About 4 times a week I go to our local YMCA and swim in the indoor lap pool. When I started swimming I could hardly swim a length of the pool without stoping to rest, but over time I worked up to swimming several laps at a time without resting. As of recent, I typically swim 1/2 mile during a workout.

Now that the detox program is over I am still being very restrictive of what foods I eat. I do eat some meat, but I try to limit it to organic beef, chicken, or turkey and wild fish. I still try not to eat sugars, dairy, or carbs. So, what do I eat and drink then? Here are some items that I enjoy...

  • Humus with vegetables
  • Guacamole with vegetables
  • Raw cashews and cranberries or raisins
  • Rice Cake with turkey and avocado
  • Rice Cake with almond Butter
  • Brown rice sushi
  • Black been salad and Shish Kabobs
  • Blueberries, almond Butter, and stevia
  • Lime water with stevia
  • Water with blueberries at the bottom
  • Dandy Blend with stevia in place of coffee
  • LÄRABAR for a snack
  • Apple and almond butter
  • Etc...

In addition to the above items a lot of what we eat these days comes from the MaximizedLiving Nutrition Plans cookbook.

As a developer who speaks regularly, I am finding it difficult to find things I can eat while I'm away from home. It seems everything is fried, has carbohydrates, or added sugar. I typically bring with me several snack baggies of nuts, dried fruit, and lara bars. I keep my pockets full of stevia packets just in case I need it while away from home.

If you know you are overweight and have been looking for a reason to change your life, I encourage you to start now. Maybe you can start by cutting out sugar drinks, cut out that late night snack, or start exercing in your home or at the gym. Whatever you do, please do something to take care of your body. Your family is counting on you to be alive.

Wednesday, April 04, 2012

Orlando Code Camp JavaScript Sessions

I was honored to be asked by Esteban Garcia (@EstebanFGarcia) to speak at the Orlando Code Camp on March 31, 2012.

I was impressed that there were 13 simultaneous tracks that were running all day long! One of the tracks was JavaScript and that is where I stayed pretty much stayed.
I presented 2 sessions Extending Your jQuery Application with AmplifyJS and Find Common jQuery Bugs. You can find the slides for these presentations online:

  • Extending Your jQuery Application with AmplifyJS - This session takes an existing web application and slow enhances it with with the 3 components of AmplifyJS. I introduce the observer pattern using amplify.publish/amplify.subscribe, I show how to use the amplify.store to support HTML5 persistant storage that is cross-browser, and I show amplify.request which is a high level abstraction to $.ajax that provides ease of configuration, mocking, prototyping, and hooks to protect against future changes.
  • Find Common jQuery Bugs - jQuery is so easy to use and thankfully abstracts many of the cross-browser concerns we used to labor over years ago. However, as with any library there are a common set of bugs that tend to crop up the more you use it. This session aims to help equip developers with the appropriate knowledge and tools to exterminate many common bugs seen in jQuery code. For each topic that is covered we will start with a piece of code that has a jQuery bug, then identify what the bug is, explain why it is happening, and then proceed to explore various techniques to exterminate the bug.

Kevin Griffin (@1kevgriff) started the day with a beginner "Zero to Hero in jQuery" talk. Even though jQuery has been around for years, it still can pack a room! Kevin had a lot of question from the audience and engaged them well.

John Papa (@john_papa) was the keynote speaker and gave an overview on the state of the web. He gave a good high level view of the technologies that are used today in modern front-end applications. John also gave the following 2 JavaScript presentations that were standing room only:

In addition John has done an in-depth Pluralsight series on Knockout and he is currently working on a series for JsRender that should be available May 2012.

There was a large crown of attendees at the conference. I heard that over 750 people signed-up to attend. That is extremely impressive and the conference was FREE too! It takes a lot of hard work, determination, and donations from generous sponsors to have something like that succeed. I want to thank Esteban Garcia and his team for the great job that they did.

Thursday, March 15, 2012

Find the jQuery Bug #8: Suspicious Selectors

Introduction


In this open-ended series I'll be showcasing a snippet of buggy jQuery code that you might encounter, explain what the problem is, and then identify how you can easily resolve the issue.

You can view other posts in this series...

The Desired Feature


The following is a snippet of HTML markup that was generated by Oracle's JSF (JavaServer Faces). We want to select the first name field and add a class that will change it's border style.


The Buggy Code


The following code snippets is our first attempt at solving the problem, but there is a subtle error. Do you see it?


You can view, run, and edit the above code sample from JSBin.



The result that we expected was to see the first name textbox with a red border, but as you can see above it was not successful.

The Underlying Problem


At the root of the problem is that JSF inserts a : delimiter inside of the id attribute. jQuery abides by the W3C CSS Specification Rules when it comes to valid characters in a selector.

If your ID, name, or class contains one of the following meta-characters then you have a problem... !"#$%&'()*+,./:;<=>?@[\]^`{|}~

Here are some examples of invalid selectors in jQuery because they contain invalid characters:


A Solution


jQuery provides a solution of escaping invalid characters inside a selector. You can proceed each character with two backslashes \\ and then the selector should start working as you expect.

If you wish to use any of the meta-characters ( such as !"#$%&'()*+,./:;<=>?@[\]^`{|}~ ) as a literal part of a name, you must escape the character with two backslashes: \\. For example, if you have an element with id="foo.bar", you can use the selector $("#foo\\.bar").

-- http://api.jquery.com/category/selectors/

In order to fix our example we just need to escape the : character with \\ like the following code example demonstrates.


You can view, run, and edit the above code sample from JSBin.

If you test out the code again below you'll notice that once you've filled in the textbox and click enter then the behavior will continue as we expected.



The following examples are the corrected versions of the previous snippets shown in the previous section:


An Alternate Solution


An alternate way to look at this problem is to create a method that will automatically escape the id, name, or class name before using it as a selector.


The previous code snippet extends the String prototype and uses a regular expression to find all invalid meta-characters and escapes them with \\.

Conclusion


The key concept to remember here is that there is a set of characters that are invalid and need to be escaped before using them in a jQuery selector.

Until next time...

Wednesday, March 14, 2012

Find the jQuery Bug #7: Using a Method as an Event Handler

Introduction


In this open-ended series I'll be showcasing a snippet of buggy jQuery code that you might encounter, explain what the problem is, and then identify how you can easily resolve the issue.

You can view other posts in this series...

The Desired Feature


We want to use an existing object's method to be invoked when the user clicks on a button.


The Buggy Code


The following code snippets is our first attempt at solving the problem, but there is a subtle error. Do you see it?


You can view, run, and edit the above code sample from the following embedded jsFiddle.



The result that we expected was to see was an alert box showing up when the user clicks the Register button, but instead the following error shows up in the console.


The Underlying Problem


At the root of the problem is that once the event handler is invoked jQuery makes sure the this pseudo parameter is set to the DOM element that caused the event.


Inside of the conference.register method listed above, the this parameter refers to the register button DOM element. Since this is a DOM element that is why we are getting the "Cannot call method 'push' of undefined" error.

What we need to resolve this issue is a way to control the value of the this parameter when the conference.register method is invoked. Thankfully, there is a way in jQuery to do this.

A Solution


The solution to fix this problem is really simple and straightforward. As of version 1.4, jQuery added the $.proxy() method to help solve the bug found in the previous example.

jQuery.proxy( function, context )
Returns: Function
Takes a function and returns a new one that will always have a particular context.

-- http://api.jquery.com/jQuery.proxy/

In order to fix our example we just need to wrap the conference.register method with the $.proxy() method and provide the context that we want the pseudo this parameter to represent.


You can view, run, and edit the above code sample from JSBin.

If you test out the code again below you'll notice that once you've filled in the textbox and click enter then the behavior will continue as we expected.



Alternate Solutions


The above solution shows how you can use the $.proxy() method to solve the problem, but technically you could have used a plain JavaScript technique instead. By using the .call() or .apply() methods in JavaScript you can control what the value of the this parameter will be just like we did with the $.proxy() method.

The following code snippet shows how you can use the .call() method to control the this parameter.


In a very similar way the next snippet of code shows how you can use the .apply() method as an alternate solution.

NOTE: While the syntax of this function is almost identical to that of call(), the fundamental difference is that call() accepts an argument list, while apply() accepts a single array of arguments. -- https://developer.mozilla.org/...


You can view, run, and edit the above code sample from jsFiddle.

Conclusion


The key concept to remember here is that if you ever need to control the value of the pseudo this paramater inside an event handlers, then you can use the $.proxy() method in jQuery. In addition, you could just use the .call() or .apply() methods in JavaScript if you would rather not use the $.proxy() method.

Until next time...

Monday, March 12, 2012

Find the jQuery Bug #6: Traversing Trouble

Introduction


In this open-ended series I'll be showcasing a snippet of buggy jQuery code that you might encounter, explain what the problem is, and then identify how you can easily resolve the issue.

You can view other posts in this series...

The Desired Feature


We want to take the following list of jQuery board and team members and then hide only those that are team members, leaving only the board members showing.


The Buggy Code


The following code snippet is our first attempt at solving the problem, but there is a subtle error. Do you see it?


You can view, run, and edit the above code sample from jsFiddle.

The results that we expected was to only view a subset of the total list, but instead we ended up seeing all the items in the list!



The Underlying Problem


At the root of the problem is that the .find() method is used for finding elements that are descendants of the current jQuery collection.

.find( selector )
Returns: jQuery
Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element.

-- http://api.jquery.com/find/

The above code snippet already starts with a jQuery collection of 22 items referenced by the $items variable. When calling the $item.find( ".team" ) method jQuery looks for all elements containing the team class that are children of it's internal collection. In this case, the list items do not have any children, so the result is an empty jQuery collection.

It is important to note that jQuery allows you to call methods off of any jQuery collection even if it is empty. The thing is that it just doesn't do anything, it silently fails. What we really need to solve this problem is to have some way to narrow down the internal jQuery collection based on a specified criteria. Thankfully, there is an easy way to do this.

A Solution


The solution to fix this problem is really simple and straightforward. The main problem is that we were using the wrong method.

We should have been using the .filter() method instead, which takes the current jQuery collection and filters them by matching against a provided selector. It doesn't traverse the children at all, but it's only purpose is to reduce the number of top level elements currently captured in the jQuery collection.

.filter( selector )
Returns: jQuery
Reduce the set of matched elements to those that match the selector or pass the function's test.

-- http://api.jquery.com/filter/

All you really need to do is to use the .filter() method instead of the .find() as we used in the previous example.


You can view, run, and edit the above code sample from JSBin.

If you test out the code again below you'll notice that the list items with class of team are targeted and hidden like we wanted!



Conclusion


The key concept to remember here is that the .find() method is for traversing into the DOM and locating descendants that match a criteria and the .filter() method is used to reduced the elements that are already selected that match a criteria.

This may seem like a trivial concept to grasp by some, but I've seen this common confusion of the two methods numerous times. I find that many developers expect that the .find() method will perform both filter and find, but it doesn't.

Until next time...

Tuesday, March 06, 2012

Find the jQuery Bug #5: Defective Data

Introduction


In this open-ended series I'll be showcasing a snippet of buggy jQuery code that you might encounter, explain what the problem is, and then identify how you can easily resolve the issue.

You can view other posts in this series...

The Desired Feature


We want to build a simple jQuery Plugin that will add a confirm message to a simple button or anchor.


The Buggy Code


The following code snippet is our first attempt at building the plugin, but there is a subtle error. Do you see it?


You can view, run, and edit the above code sample from jsFiddle.

The developer initialized the buttons on the page and then wanted to update the prompt for the first button. He removed all the event handlers added by the plugin, updated the attribute, and then re-initialized the button with the plugin. Unfortunately, this technique didn't work as intended.

The Underlying Problem


At the root of the problem is an issue when trying to use the .attr() method after already using the .data() method.

"Only the .data() API reads HTML5 data-* attributes, and it does so once." -- Dave Methvin http://www.learningjquery.com/...

The jQuery plugin reads the HTML5 data-* attribute first, and the developer tried to update the data-* attribute later with the .attr() method. Once the jQuery plugin is re-initialized on the DOM element it will not read the data-* attribute again, but instead use the data it retrieved the first time.

A Solution


The solution to fix this problem is really simple and straightforward. All you really need to do is to change the code where the data-* attribute was updated to use the .data() method instead of the .attr() method.


You can view, run, and edit the above code sample from jsFiddle.

If you test out the code again below you'll notice that it behaves as expected. When you click on the button it will use the updated text that was provided before the plugin was re-initialized.

You may notice that I also changed the key parameter to the .data() method to camelCase instead of the dashed version I had previously. As of jQuery 1.6 the library has changed direction in how they deal with HTML5 data-* attributes.

"The treatment of attributes with embedded dashes was changed in jQuery 1.6 to conform to the W3C HTML5 specification." -- http://api.jquery.com/data...

Now, you can still reference that HTML5 data-* attributes using their dashed keys, but jQuery will first attempt to use the key "as is" and only attempt to convert that to a camelCased version if it failed. See the following comment from the Dave's article I referenced above.

"Because many people will use .data( "camel-case" ) instead, we convert that to camelCase as well, but only if no data item named camel-case is found so it's faster to use the first form." -- Dave Methvin http://www.learningjquery.com/...

Other Things You Might Want to Know


Something that you also may not know about the $.data() method is that it will attempt to convert the contents of a HTML5 data-* attributes into the appropriate type.

"Every attempt is made to convert the string to a JavaScript value (this includes booleans, numbers, objects, arrays, and null) otherwise it is left as a string. To retrieve the value's attribute as a string without any attempt to convert it, use the .attr() method." -- http://api.jquery.com/data...

The following example shows a DOM element using various types of HTML5 data-* attributes, and then shows that when you call the .data() method to retrieve a value it will parse and convert it into a boolean, number, object, array, or null.



You can view, run, and edit the above code sample from jsFiddle.

If for some reason you didn't want jQuery to convert the HTML data-* attributes when using the .data() method, you could use the .attr() method instead. The .attr() method will always return the string version of the attribute.

Conclusion


The key concept to remember here is that once you call the .data() getter method on a element then it will read the HTML5 data-* atributes only once. If you want to update the data from there on, then you'll need to use the .data() setter method. Also, it is important to know that when you read these HTML5 data-* attributes jQuery will convert those values into it's appropriate type.

I hope you found this helpful. I recommend you reading Dave Methvin's article entitled Using jQuery’s Data APIs.

Please provide any feedback in the comments below. Until next time...

Monday, February 27, 2012

TextMate-like ⌘T & ⇧⌘T in Chrome Dev Tools & Other New Features

Introduction


For the past year or so I've used Google Chrome Canary as my primary web browser, however, about a month ago I temporarily switched to the stable build of Chrome because of some instability in the dev tools. I just recently switched back to Canary and was pleasantly surprised to see numerous new features in the dev tools there were very welcome indeed!

This post only covers the extreme latest in Chrome Dev Tools. There are so many more rich features that can be found. If you are interested about more helpful features you might be interested in a post I did last year entitled 7 Chrome Tips Developers & Designers May Not Know

If you are not familiar with the Canary build of Chrome, it is a extremely dev version of the browser. You should be cautious because it does update almost every day, but at the same time you get first in line to see all the new features. Unlike the dev or beta builds of Chrome you can actually install Canary side-by-side next to your Stable or Beta build of Chrome. This makes switching between versions very convenient.

The features I am about to describe are currently only available in the dev or canary builds of Chrome. If you have the Beta or Stable builds then you will not see these yet, but hopefully they'll make their way to those builds sooner than later. At least this will wet your appetite ;)

Scripts Explorer


A welcome change to the Scripts tab is a new Scripts Explorer (as seen in the below image). The previous way to navigate through the scripts of a webpage was to open a HUGE drop down containing tons of script files. Chrome kept reorganizing that huge drop-down list to make it more usable, but in the end it wasn't optimal when dealing with a site with lots of JavaScript fiels.

The new Scripts Explorer nicely separates the Scripts used on the webpage from the Content Scripts used in all of the Chrome Extensions you have installed in your browser. Historically, it was slightly annoying to see all those Content Scripts alongside your main JavaScript files in that huge drop down mentioned above. Again, over time Chrome moved those Content Scripts to the bottom of that drop down instead of intermingled, but this move to the Scripts Explorer is head over heals WAY better... YAY!

In addition, you can also choose to dock the Scripts Explorer to the left side of the dev tools (by clicking the little icon in the upper right) or have it auto-close when you are done finding what you need.


TextMate's ⌘T "Go to File" Feature


I don't know about you, but I'm one of those keyboard shortcut junkies, so I am always on the lookout on how to do my job without using the mouse. So, I was even more excited to see support for quickly finding a JavaScript file by only using the keyboard! Chrome call's this feature "Go to Script" and it is similar to what you may have experience in TextMate using ⌘T or maybe in Sublime Text 2 with ⌘P.

Since ⌘T is already reserved for creating a new tab in Chrome, they have chosen ⌘O for this feature. As soon as you type ⌘O you will see the following dialog displaying JavaScript files. As you type the list will filter to only the files that match what you are typing. You can arrow up or down to narrow the selection even more and then click "enter" to open that script file.


TextMate's ⇧⌘T "Go to Symbol" Feature


Now, if the "Go to Script" feature wasn't enough, there is also the "Go to Function", which is similar to the "Go to Symbol" feature of TextMate using ⇧⌘T or ⌘R in Sublime Text 2.

Once you are in a JavaScript file you can press ⇧⌘O to bring up the "Go to Function" dialog. This works in a very similar way as the "Go to Script" dialog as we saw previously, but this time instead of looking for files, it helps you track down functions! Navigating through your JavaScript files to find a specific function has now become a breeze!


Dock Dev Tools to the Right


The last feature that stood out to me as really cool, was the new setting to "Dock to right". Many people these days have a wide-screen monitor and having the dev tools docked at the bottom of the screen sometimes feels a little scrunched. If I have my browser maximized there is usually tons of room to the left or right of the website I am viewing.

Thankfully, with this new feature I can now choose to dock the dev tool to the right of my screen to give some breathing room for development!

Note: I undrestand some like to undock the dev tools to solve this issue, but I usually tend to like keeping them docked so this new feature is very handy for me.


In order to turn on this feature, you'll need to go into the Settings dialog. You can access this by clicking on the gear icon located at the bottom right of your dev tools. Once the dialog has been launched you should see a General section with the "Doc to right" option listed.


Conclusion


I find the the above JavaScript enhancements to the dev tools have really made navigating through scripts to be much more enjoyable. If you have noticed any other new features that I have missed please let me know. They keep cropping up all the time... which is AWESOME!

If you have Chrome Canary then you can start using the above features right way, otherwise they should make it in a Beta or Stable build in the near future.

Monday, February 13, 2012

Find the jQuery Bug #4: Animations Gone Wild

Introduction


In this open-ended series I'll be showcasing a snippet of buggy jQuery code that you might encounter, explain what the problem is, and then identify how you can easily resolve the issue.

You can view other posts in this series...

The Desired Feature


We want to take the following HTML and build a simple jQuery menu that will reveal sub-menus when you hover over each item.


The Buggy Code


The following code snippet is our first attempt at solving the problem, but there is a subtle error. Do you see it?


If you start playing with the menu it appears that it works as intended, but as you continue to use the menu an annoying problem raises its ugly head. If you move your mouse really quick from right to left over the menu you'll see the problem :(



The Underlying Problem


If you played with the example above you'll have noticed that if you interact with the menu really quickly side-to-side then the animations continue over and over and over again, even after you've moved off the menu completely!

At the root of the problem is an animation queue that has gotten out of hand. jQuery keeps an internal queue to help it know what animation to run next. When you take an element and call one of the animation methods ( .animate(), .slideDown(), .slideUp(), .slideToggle(), etc... ) what really happens is that effect gets added to the default "fx" animation queue that is attached to the element. As each effects completes jQuery will move on to the next effect in the queue until all animations are complete.

The magic that we need is to somehow interrupt the queue system. Thankfully, there is an API just for that and in the next section we will show how to use it.

A Solution


The solution to fix this problem is really simple and straightforward. In the words of Bob Newhart, we need the animation to STOP IT!

Of course, we can tell our program to STOP IT!, but they are usually to stubborn to heed to our warnings. Thankfully there is a method we can utilize in jQuery coincidentally called .stop() which we can use to solve our animation problem!

The following is the documentation from jQuery's website about the .stop() method that we will use.

.stop( [clearQueue] [, jumpToEnd] )
version added: 1.2
clearQueue - A Boolean indicating whether to remove queued animation as well. Defaults to false.
jumpToEnd - A Boolean indicating whether to complete the current animation immediately. Defaults to false.

.stop( [queue] [, clearQueue] [, jumpToEnd] )
version added: 1.7
queue - The name of the queue in which to stop animations.
clear - QueueA Boolean indicating whether to remove queued animation as well. Defaults to false.
jumpToEnd - A Boolean indicating whether to complete the current animation immediately. Defaults to false.

--http://api.jquery.com/stop/

As you see above there are 2 "overloaded" methods both with optional parameters. The important parameters that we will use to fix our code snippet are the clearQueue and jumpToEnd booleans. In order to get rid of the huge queue of animations on an element and complete whatever animation that was started all we need to do is pass true as both parameters... $element.stop( true, true )!


If you test out the code again below you'll notice that it works just as before, but this time the bug we found when moving our mouse quickly back and forth across the menu is now gone!



A Fancy Solution


If we wanted to get fancy, we could choose to update the animation easing algorithm. An easing algorithm is a mathematical equation that defines the animation path of an effect. Wow, that was a mouth full. Let's try that again, but this time with something visual. The following demo, from jQuery UI, is a great visualization of the various easing algorithms. Click the image to launch the jQuery UI Easing Demo and then click on each square to view the easing in action. I think my favorite is "easeOutBounce" ;)


With these easing options in mind, let's update our example above and use "easeOutBounce" instead of the default "swing" option that is default in jQuery.

NOTE: "The only easing implementations in the jQuery library are the default, called swing, and one that progresses at a constant pace, called linear."

-- http://api.jquery.com/slideDown


You might notice that I also added some other parameters to the .slideDown() and .slideUp() methods. All of the parameters are optional, but if we want we can provide our own values such as a duration, easing algorithm, and a callback to invoke when the animation is complete. In the code above, I trigger a custom event depending if the sub-menu was opened or closed and then I delegate to those events using the .on() method on line 19.

.slideDown( [duration] [, easing] [, callback] )
version added: 1.4.3
.slideUp( [duration] [, easing] [, callback] )
version added: 1.4.3
duration - A string or number determining how long the animation will run.
easing - A string indicating which easing function to use for the transition.
callback - A function to call once the animation is complete.

-- http://api.jquery.com/slideDown/ & http://api.jquery.com/slideUp/

Now you can test the changes we made. The effect may be too adventurous for most production business web applications, but the one I chose is just one of the many easing algorithms provided by jQuery UI that you can pick from. Also, if you are a math wizard you can come up with your algorithm!



Refactoring the Code


If you are anything like me you probably noticed a code smell. Much of the code from the previous examples looks very redundant. Let's take a stab at refactoring the code somewhat to reduce the "duplicated code" smell and made the code DRY (don't repeat yourself).

If you look through your vast code base, And notice code repeated here and there.
You might consider refactoring soon, Or you'll experience maintenance despair!

Previously we were passing two functions to the .hover() method. The 1st function parameter was to handle mouseover events and the other was to handle mouseout events. Thankfully, there is another "overloaded" version of .hover() that takes just 1 function parameter. This 1 function will be invoked on both mouseover events and mouseout events!


You may also notice that we are using a different method to actually perform the sub-menu animation. jQuery includes a .slideToggle() method that will either .slideDown() or .slideUp() depending on the state of the element.

The last thing to take into consideration is how to know which custom event to trigger. Previously I knew which event to trigger because opened was associated with .slideDown() and closed was associated with .slideUp(), but what about now? Thankfully that is easily solved by looking at the event object passed to the hover event handler. The event object has a type property which tells what type of event was originally fired. So, I can do something like this... e.type === "mouseover" ? "opened" : "closed" -- http://jsfiddle.net/ujsfH/

Conclusion


The key concept to remember here is that jQuery has an internal animation queue that you should be aware of. If you need to clear out that queue you can use the .stop() method. Also, you can modify the duration of animation, change the animation easing algorithm, and also respond to an event when the animation is complete.

Things we didn't cover in this post are how to create your own queue, how to create your own easing algorithm, how to modify the default animation duration, and several other concerns.

Until next time...

NOTE: The CSS I used as the base for the example menu above is a modified version from a blog post on @Kriesi's website. I removed the hover styles and replaced his jQuery code with mine for this Find the jQuery Bug post.

Wednesday, February 08, 2012

Regular Expressions in CoffeeScript are Awesome

Let's face it, regular expressions aren't for everyone. It takes a special breed of developer to actually enjoy writing regular expressions. Although I enjoy them, the developer that comes after me may find that they are cryptic and hard to read. And yes, sometimes it takes me a little bit to decipher through an old regular expression that I wrote a while ago.

Take for example, the following regular expression. Can you tell what it is doing? If so... then great, but what about the developers you work with?


One of the very cool things I like about CoffeeScript is that you can annotate your regular expressions! The following snippet of CoffeeScript compiles down to the equivalent JavaScript as seen in the above code sample. Yay ;)


Which code sample would you rather maintain? And more importantly which one would your co-worker be more likely to understand?

NOTE: The above email regular expression is very naive in it's logic. I based the above snippet from a Nettuts+ post entitled, 8 Regular Expressions You Should Know. There are much more comprehensive email regular expressions available on the internet, but I used the above one to show the value of annotation.

As a side note, some tools that I find helpful are Grant Skinner's Online RegExr Tool and I sometimes get inspiration for regular expressions at RegExLib.com. What tools or resources do you use for regular expressions?

Monday, February 06, 2012

Differences Between jQuery .bind() vs .live() vs .delegate() vs .on()

Introduction


I've seen quite a bit of confusion from developers about what the real differences are between the jQuery .bind(), .live(), .delegate(), and .on() methods and when they should be used.

If you want, you can jump to the TL;DR section and get a high-level overview what this article is about.

Before we dive into the ins and outs of these methods, let's start with some common HTML markup that we'll be using as we write sample jQuery code.


Using the Bind Method


The .bind() method registers the type of event and an event handler directly to the DOM element in question. This method has been around the longest and in its day it was a nice abstraction around the various cross-browser issues that existed. This method is still very handy when wiring-up event handlers, but there are various performance concerns as are listed below.


The .bind() method will attach the event handler to all of the anchors that are matched! That is not good. Not only is that expensive to implicitly iterate over all of those items to attach an event handler, but it is also wasteful since it is the same event handler over and over again.

Pros
  • This methods works across various browser implementations.
  • It is pretty easy and quick to wire-up event handlers.
  • The shorthand methods (.click(), .hover(), etc...) make it even easier to wire-up event handlers.
  • For a simple ID selector, using .bind() not only wires-up quickly, but also when the event fires the event handler is invoked almost immediately.

Cons
  • The method attaches the same event handler to every matched element in the selection.
  • It doesn't work for elements added dynamically that matches the same selector.
  • There are performance concerns when dealing with a large selection.
  • The attachment is done upfront which can have performance issues on page load.

Using the Live Method


The .live() method uses the concept of event delegation to perform its so called "magic". The way you call .live() looks just like how you might call .bind(), which is very convenient. However, under the covers this method works much different. The .live method attaches the event handler to the root level document along with the associated selector and event information. By registering this information on the document it allows one event handler to be used for all events that have bubbled (a.k.a. delegated, propagated) up to it. Once an event has bubbled up to the document jQuery looks at the selector/event metadata to determine which handler it should invoke, if any. This extra work has some impact on performance at the point of user interaction, but the initial register process is fairly speedy.


The good thing about this code as compared to the .bind() example above is that it is only attaching the event handler once to the document instead of multiple times. This not only is faster, but less wasteful, however, there are many problems with using this method and they are outlined below.

Pros
  • There is only one event handler registered instead of the numerous event handlers that could have been registered with the .bind() method.
  • The upgrade path from .bind() to .live() is very small. All you have to do is replace "bind" to "live".
  • Elements dynamically added to the DOM that match the selector magically work because the real information was registered on the document.
  • You can wire-up event handlers before the document ready event helping you utilize possibly unused time.

Cons
  • This method is deprecated as of jQuery 1.7 and you should start phasing out its use in your code.
  • Chaining is not properly supported using this method.
  • The selection that is made is basically thrown away since it is only used to register the event handler on the document.
  • Using event.stopPropagation() is no longer helpful because the event has already delegated all the way up to the document.
  • Since all selector/event information is attached to the document once an event does occur jQuery has match through its large metadata store using the matchesSelector method to determine which event handler to invoke, if any.
  • Your events always delegate all the way up to the document. This can affect performance if your DOM is deep.

Using the Delegate Method


The .delegate() method behaves in a similar fashion to the .live() method, but instead of attaching the selector/event information to the document, you can choose where it is anchored. Just like the .live() method, this technique uses event delegation to work correctly.

If you skipped over the explanation of the .live() method you might want to go back up and read it as I described some of the internal logic that happen.


The .delegate() method is very powerful. The above code will attach the event handler to the unordered list ("#members") along with the selector/event information. This is much more efficient than the .live() method that always attaches the information to the document. In addition a lot of other problematic issues were resolved by introducing the .delegate() method. See the following outline for a detailed list.

Pros
  • You have the option of choosing where to attach the selector/event information.
  • The selection isn't actually performed up front, but is only used to register onto the root element.
  • Chaining is supported correctly.
  • jQuery still needs to iterate over the selector/event data to determine a match, but since you can choose where the root is the amount of data to sort through can be much smaller.
  • Since this technique uses event delegation, it can work with dynamically added elements to the DOM where the selectors match.
  • As long as you delegate against the document you can also wire-up event handlers before the document ready event.

Cons
  • Changing from a .bind() to a .delegate() method isn't as straight forward.
  • There is still the concern of jQuery having to figure out, using the matchesSelector method, which event handler to invoke based on the selector/event information stored at the root element. However, the metadata stored at the root element should be considerably smaller compared to using the .live() method.

Using the On Method


Did you know that the jQuery .bind(), .live(), and .delegate() methods are just one line pass throughs to the new jQuery 1.7 .on() method? The same is true of the .unbind(), .die(), and .undelegate() methods. The following code snippet is taken from the jQuery 1.7.1 codebase in GitHub...


With that in mind, the usage of the new .on() method looks something like the following...


You'll notice that depending how I call the .on() method changes how it performs. You can consider the .on() method as being "overloaded" with different signatures, which in turn changes how the event binding is wired-up. The .on method bring a lot of consistency to the API and hopefully makes things slightly less confusing.

Pros
  • Brings uniformity to the various event binding methods.
  • Simplifies the jQuery code base and removes one level of redirection since the .bind(), .live(), and .delegate() call this method under the covers.
  • Still provides all the goodness of the .delegate() method, while still providing support for the .bind() method if you need it.

Cons
  • Brings confusion because the behavior changes based on how you call the method.

Conclusion (tl;dr)


If you have been confused about the various different types of event binding methods then don't worry, there has been a lot of history and evolvement in the API over time. There are many people that view these methods as magic, but once you uncover some of how they work it will help you understand how to better ode inside of your projects.

The biggest take aways from this article are that...
  • Using the .bind() method is very costly as it attaches the same event handler to every item matched in your selector.
  • You should stop using the .live() method as it is deprecated and has a lot of problems with it.
  • The .delegate() method gives a lot of "bang for your buck" when dealing with performance and reacting to dynamically added elements.
  • That the new .on() method is mostly syntax sugar that can mimic .bind(), .live(), or .delegate() depending on how you call it.
  • The new direction is to use the new .on method. Get familiar with the syntax and start using it on all your jQuery 1.7+ projects.





Were there any pros or cons that you would have added to the above lists? Have you found yourself using the .delegate method more recently? What are you thoughts on the new .on method? Leave your thoughts in the comments. Thanks!