A Better Default Value jQuery Plugin

Recently I forked Doug Neiner's inFieldLabels plugin to try and make it a little bit more automatic than it was, which has proved to be problematic. After having used my fork in a couple of sites, I have found that it is more trouble than it's worth to do the absolute positioning like I did. It specifically doesn't work well when things are moving on the screen, such as expanding hidden DOM elements, which cause the label to stay put while the form element moves. I thought about fixing it to detect those kinds of movements and handle some other edge cases that were reported to me, but I felt like the plugin was going to get way more complicated than it needed to be to accomplish a seemingly simple task. I was very happy to find Jan Jarfalk's Defaultvalue plugin, which is a much simpler implementation and works like a champ. No special styling or DOM elements required. It accomplished what I wanted to do in a much more elegant manner. I have successfully replaced inFieldLabels with it on my projects and I am no longer experiencing any of the styling or positioning hassles. There was one quirk with it though. Since it actually fills in an input field with the default value, if that value is present in the field when it posts, that value will be sent to the server. I made a minor update to it to account for this and submitted it back to the author. I hope he incorporates it into his plugin, but we'll see. In the meantime, you can patch it by chaining in the following code to line 37 right after the call to focus, which will cause it to clear the default upon form submit if it is still present in the field. [js] //end of focus event }).closest("form").submit(function() { self.val() == defaultValue && self.val(''); }); [/js] There is some additional nit-picky cleanup that could be done in the plugin as well, but overall it looks, and more importantly works, very good. Kudos to Jan for putting it together and sharing it!

Using ".call" in JavaScript

Every so often I find myself binding a function to an event, but I want to also run that function on page load. Sometimes you can just invoke the event right away, like this: [js] $(".some_element").change(function() { //do something }).change(); [/js] That can have side effects that you don't want though, such as executing other functions unintentionally. In that case, you can name the function and call it explicitly after the bind, like this: [js] function doSomething() { //do something } $(".some_element").change(doSomething); doSomething(); [/js] That has another problem though. If you were using "this" and expecting it to be the changed element (which you probably were), then that context won't be set. Luckily, there is an easy way to get around that as well. You can invoke the function in a different way and set the context to be a specific DOM element, just like jQuery itself does. [js] $(".some_element").change(doSomething).each(function() { doSomething.call(this); }); [/js] This way, you can write the function assuming the context of this like you normally would and still directly invoke it as need be.

Are you using jQuery.extend properly?

jQuery's extend function is pretty powerful for merging objects and it is the hinge that plugins rely on to operate. It is very easy to use, but if you don't understand exactly what it does, it can come back and bite you. The first case for using the method is to extend the jQuery object itself. Calling it on jQuery or jQuery.fn will add functions to the jQuery namespace or jQuery objects, respectively. The second case is to merge objects together. You can do this by calling extend with multiple parameters. The first parameter is considered to be the base and all subsequent ones are merged into it in order. The updated object is also returned. The important thing to be aware of is that the first parameter will be updated by this call. For example, if you have an object in your plugin that has its defaults stored in an object and you pass that in as the first argument, then it will by updated by the parameters passed in. The wrong way to do it, causing your defaults to be rewritten: [js] var defaults = { some: 'option' }; function myPlugin(user_options) { var options = $.extend(defaults, user_options); ... } [/js] Instead, the safe way to call extend in that instance is like this: [js] var options = $.extend({}, defaults, user_options); [/js] That will cause the user options to override the defaults without rewriting them and store it in another variable for your use.

jQuery Curtain 0.5.2

Just a few small changes.
  • Streamlined the code for removing curtains, which might be a small performance boost.
  • Removed an unnecessary call to makeArray in the get code.
  • Changed it to add the image as a hidden element then show it after it finishes loading. This is to prevent the user from seeing the image flash from the top left corner to the center of the screen in certain instances.
  • Most importantly, I fixed a bug that was causing the passed in options to be discarded.
On a side note, I have received some feedback recently about the API being a little "unclean". I was told (and I completely agree) that the passing in of strings to initiate certain specific actions is not a good way of doing that. I was thinking about this today and I see two alternative ways to implement this. The first is to have three separate functions.
  • The curtain() function that would create the curtains and return the curtained elements.
  • A curtainRemove() that would remove the curtains.
  • A curtainRetrieve() that would return the curtains instead of the curtained elements.
I am personally opposed to this approach, as having three separate functions for this plugin, in my opinion, muddies up the jQuery waters. The other solution I came up with is to change the curtain() function to return the curtains instead of the curtained elements. This seems like a better solution from an API perspective, but it would break your ability to chain the curtain call with other calls on the curtained objects. That isn't necessarily a big deal as certain functions already break the ability to chain. If we do that, then the API would just have curtain({options}), which would double as creating them and getting them. You could then call $("...").curtain().remove(); to destroy them all. Breaking the chaining seems like the cleanest solution to me. If you have any thoughts on the subject, please e-mail me, tweet me, or leave a comment.

Scoping Functions in Document Ready

When writing your event handlers in your document ready, it sometimes happens that you have the same functionality bound in a few different places. It is really easy to make a function that is not visible outside of your document ready but that allows you to reuse that code. Let's say, for example, that you have a link's click event and input field's keypress event that both need do the same simple action. We definitely want to reuse the same code for both places, but don't want the function exposed to the whole world. The easy thing to do is just declare the function in the bottom of your document ready's anonymous function, like so: [js] $(function() { $("a").click(doSomething); $(":text").keypress(doSomething); function doSomething() { console.log("we did something!"); }; }); [/js] This way, we have a local function that is accessible only from inside the document ready block. Reducing the scope like that will prevent accidental usage in other places, but still keep the code clean.

New Fork of InFieldLabels jQuery Plugin

I recently found an excellent plugin written by Doug Neiner for applying a label over an input field that appears as a default value. Implementing it as a label instead of defaulting the value of the input element is a better approach, IMO, because it allow you flexibility for animating the text and it will also work on password fields without showing ****. It isn't too difficult to use. All you need to do is have a container that is relatively positioned and contains a label and input field. The label should be absolutely positioned and you need to, in your css, make it hover correctly over the input. This also required you to calculate the margin, border, and padding of the input and apply the same to the label otherwise the text wouldn't line up. When I started rolling it out on a site I was working on, however, I quickly found that the special requirements for the label and its container proved challenging to mix with my existing designs. I thought it would be much better if the usage of the plugin was flipped around and instead of calling it on the label, you called it on the input itself and everything else just happened automagically. So, I forked the project and made the changes to support this approach. I won't go into too much detail here, as I explained it in the README of the project itself, but now all you need to do is have any input on the screen and call it like this: [js] $(":input").inFieldLabels("label text"); [/js] Doing that will insert an absolutely positioned label into the base of the body, calculate the position of your input and apply those values to the label, and calculate the margin, border, and padding of the input and set the padding of the label to match. This way, all you need to do is include the plugin and start using it. No special DOM structure or CSS required. The only thing to be aware of is that it does use a label tag and so you need to make sure that you set up "label.infieldlabel" in your css to match the text of your input elements. GitHub Project

Caps Lock Detection

UPDATED 2009.09.06 - Updated to support Opera Operating system logons (well OS X at least) provide a visual indicator alerting you to when you have caps lock turned on when you are typing your password. This is a pretty cool feature and it is actually really easy to implement in JavaScript. The vast majority of your users will type upper case letters in one of two ways: pressing the shift key or turning on caps lock. Following that assumption, you can easily check to see if a keypress event has the shift key pressed and what the charCode was. A simple function to detect caps lock and enable a visual cue would look something like this: [js] $(":password").keypress(function(e) { //Opera doesn't populate the charCode var charCode = e.charCode || e.which; !e.shiftKey && charCode >= 65 && charCode <= 90 ? $("#caps_lock").show() : $("#caps_lock").hide(); }); [/js] Here is the code in action:

CAPS LOCK IS ON!

Safari 4 on OS X will provide a cue for you, but adding a little extra flare to it won't hurt.

jQuery Curtain v0.5

It has been bothering me that the plugin required you to specify the dimensions of the image. The reason I wrote it that way was because the image wasn't loaded yet when it was added to the page, so we didn't have the dimensions. I have finally had the opportunity to enhance it to calculate those dimensions for you whether the image was preloaded or not. The fix was to attach the javascript that gets the image size in a "load" event handler on the new image. Since it is added to the DOM every time, it will always be fired. Enjoy the new version and let me know if you have any feature requests or bugs!

jQuery Curtain v0.4

I rolled out version 0.3 on a site I am working on last night and found an annoying issue. I had to override the default settings in every call with the same new defaults. That wasn't cool. So tonight is another release with a small but handy little addition to the plugin. You can now call $.curtainSetup(options) and override the default options. That means you can just add it once to your document ready handler and not have to keep passing in the options with every call. My code that calls curtain is now a little cleaner, which makes me happy and everyone else appreciates, too.

jQuery Curtain v0.3

When I first wrote the documentation for Curtain, it hit me that the plugin had a fatal flaw. I originally wrote it to append the curtain into the dom element being curtained. It seemed reasonable at the time. It made it such that I could easily keep track of what curtain belonged to what element without having to track ids or anything. Well as it turns out, that was a big mistake. That implementation carried with it the "feature" of not being able to add it to elements that cannot accept a child div element or to elements that had an absolute position. I have wanted to use it on table rows a few times since I released it and finally had the chance this evening to redo the implementation. If you upgrade to version 0.3, it will now append all the curtain elements to the body tag, so they are completely independent of the element being curtained. Each one receives a unique id, which is stored in the id attribute of the curtain and in a data element in the element being curtained. It actually makes the code a lot cleaner and the implementation a lot more robust. With the new way of linking curtains to the curtained elements, I added a .curtain("get") function to allow easy access to the curtain in case you need it for some reason. I needed it for the tests and I can't imagine why you would want to access it in code, but it is there for you nonetheless. On a side note, I did a little TDD and added the test for adding to absolutely positioned elements before fixing the bug. TDD rocks the house, BTW. If you aren't doing it, you should totally give it a try. Screw.Unit for javascript testing is awesome as well and fits really well with jQuery plugins. If you want to see an example of it in action, check out the spec directory under the project root on github. Just render the suite.html file in your browser to run the tests.