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.
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.
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...
We wait until the document is ready before running the rest of our code.
Once the DOM is ready, then select all the input elements on the page with the date class.
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.
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.
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.
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.
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.
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.
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.
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!
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.
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
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.
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.
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.
Open the Command Palette... Shift-Cmd-P
Choose Package Control: Install Package
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.
Open the Command Palette... Shift-Cmd-P
Choose Tweet
A browser will open and Twitter will generate an authentication token for you
Copy the authentication token and paste it into the prompt in Sublime Text
Now you are all setup for using the package
How to Use
Sending a Tweet
Open the Command Palette... Shift-Cmd-P
Choose Tweet
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.
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...
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.
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.
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.
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?
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").
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.
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.
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.
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.
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/...
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.
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.
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?
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.
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.
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.
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.
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.
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 Methvinhttp://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.
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.
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.
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.
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.
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."
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.
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.