Context: HTML widgets generated using a Django ModelForm and template, jQuery 1.3.2, JavaScript on IE8, Firefox 3.5 or Safari 4. Procedures: An ordinary JavaScript function with some jQuery inside, or jQuery Enlightenment, Cody Lindley, "Adding new functions to the jQuery namespace," p. 116.
I have a jQuery construct that is repeated several times with different variables and so has been begging to be turned into a function. Basically some of the widgets need to be enabled or disabled based on the values of other widgets. I wrote this function two ways. The first way, with jQuery code inside an ordinary JavaScript function, is as follows:
function enable_or_disable_by_selection(master_id, master_id_value, dependent_ids) {
/*
* The master_id argument is the id attribute string of the master select element in the form
* "#id_select_element_name".
* The master_id_value argument is the selection value, a string, that causes the dependent
* elements to be enabled when it is selected. In all other cases, they are disabled.
* The dependent_ids argument is an array of dependent id attribute strings, such as
* ["#id_element_1", "#id_element_2", "#id_element_3"]
*/
/* ON CHANGE OF master_id SELECTION ELEMENT: */
$(master_id).change(function() {
/* If master_id_value is chosen, enable inputs for elements in dependent_ids: */
if ($(master_id).val() == master_id_value) {
for (var i = 0; i < dependent_ids.length; i++) {
$(dependent_ids[i]).removeAttr("disabled");
}
}
/* Otherwise disable inputs for elements in dependent_ids: */
else {
for (var i = 0; i < dependent_ids.length; i++) {
$(dependent_ids[i]).attr("disabled", true);
}
}
});
}
This works. The second way, recommended by the very able Mr. Lindley, puts my new function in the jQuery namespace. His basic recommended construct may be seen here. This helps me "avoid creating global code that could potentially create conflicts." Here's the code for my function following these recommendations:
(function($){
$.enable_or_disable_by_selection = function(master_id, master_id_value, dependent_ids){
/*
* The master_id argument is the id attribute string of the master select element in the form
* "#id_select_element_name".
* The master_id_value argument is the selection value, a string, that causes the dependent
* elements to be enabled when it is selected. In all other cases, they are disabled.
* The dependent_ids argument is an array of dependent id attribute strings, such as
* ["#id_element_1", "#id_element_2", "#id_element_3"]
*/
/* CHANGE OF master_id SELECTION ELEMENT: */
$(master_id).change(function() {
/* If master_id_value is chosen, enable inputs for elements in dependent_ids: */
if ($(master_id).val() == master_id_value) {
for (var i = 0; i < dependent_ids.length; i++) {
$(dependent_ids[i]).removeAttr("disabled");
}
}
/* Otherwise disable inputs for elements in dependent_ids: */
else {
for (var i = 0; i < dependent_ids.length; i++) {
$(dependent_ids[i]).attr("disabled", true);
}
}
});
};
})(jQuery);
This works too. It's the same logic wrapped up in jQuery.
I know that jQuery makes use of anonymous functions and closures in order to maintain a hermetic namespace. See "Using (function(){})()" by John Resig, here. But, as I study these two snippets, I am having a hard time seeing the risk in the first, simpler version. Also, am I wrong in thinking that this second method is a bit slower? Please help me see the advantages in the second version. I want to know why this is done.
Useful observations not pertinent to the question are always welcome.