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.
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.
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.
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!
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.
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.