jQuery: How to disable form element, link, etc.

In this post you will learn how to disable and enable different HTML elements (input, textarea, links, etc.) using jQuery. First, let's categorize the diffent types of elements that can be disabled using jQuery. We can categorize them into 3 general categories. Method of disabling items in each category is different.

If I missed some other element that does not fall under any of those 3 categories please leave a comment. The idea behind any method is very simple though. Usually all you have to do is to change element's attribute. See example below to get an idea.


Here are the three categories that we mentioned:

  1. Form elements - input fields, textarea, buttons, select boxes, radio buttons, etc.
  2. Anchor links - make text links non clickable.
  3. Bound jQuery events - for example bound click event on a <div>.

1. Disable form elements

Consider you have a form and you need to disable some element on it. All you have to do to disable it is to add disabled property to that element (input, textarea, select, button). Let's see an example:

<form action="url" method="post">
  <input type="text" class="input-field" value=".input-field">
  <input type="button" class="button-field" value=".input-field">
  <input type="radio" class="radio-button" value=".input-radio">
  <select class="select-box">
    <option value="1">One</option>
  <select class="select-box">
</form>

jQuery code to disable form elements and enable them back:

// jQuery code to disable
$('.input-field').prop('disabled', true);
$('.button-field').prop('disabled', true);
$('.radio-button').prop('disabled', true);
$('.select-box').prop('disabled', true);

// To enable an element you need to either
// remove the disabled attribute or set it to "false"
// For jQuery versions earlier than 1.6, replace .prop() with .attr()
$('.input-field').prop('disabled', false);
$('.button-field').removeAttr('disabled');
$('.radio-button').prop('disabled', null);
$('.select-box').prop('disabled', false);

Caveats & notes

Setting form element's disabled attirbute causes browsers not to sent that element to the server on form submit. In other words, your server script will not receive that form element's value. The workaround to that problem is to sent readonly attribute instead of disabled. This will make your fields non editable, but browser will still send the data to the server.

2. Disable anchor link (<a href="" ...>)

Now, let's see how to disable a link on your page, so that when user clicks on it browser does not follow it. There 2 methods to do that:

  1. Catch click event and prevent default bahaviour;
  2. Replace link's href property to "#".

I personaly prefer the first method, but you may have different needs. Let's see both methods in action.

<!-- Consider we have this HTML -->
<a href="aboutus.html" class="internal">some internal link<a>
<a href="http://www.google.com" class="external">external link<a>
// Bind "onclick" event
$('.internal').on("click", function(e){
  e.preventDefault();
  return false;
});

// Replace link's "href" attribute
$('.external').prop('href', '#');

Caveats & notes

In the onclick example above we added e.preventDefault() method which would stop event propagation. If you have other events relying on it on parent elements, please remove that method call. Also, when setting link's new href attribute, you can save the initial value with .data() method in order to set it back later.

// Removing e.preventDefault();
$('.internal').on("click", function(e){
  return false;
});

// Recording link's "href" attribute for later use
$('.external').data('original-href', $('.external').attr('href'));
$('.external').prop('href', '#');

// Setting it back
$('.external').prop('href', $('.external').data('original-href'));

3. Unbinding bound jQuery events

Last but not least is unbinding previously bound events. This is probably the easiest of the batch. All you have to do is to use jQuery's .unbind() method. Let's see an example:

<div class="some-elem">
  Click me
</div>
// Bind "click" event
$('.some-elem').on('click', function(){
  alert("Div is clicked!");
});

// Unbind "click" event
$('.some-elem').unbind('click');

Caveats & notes

Unbinding click event will unbind all click events that were bound to that element. So, if you want to unbind only your click event, without affecting others you have 2 options:

  1. Namespace your events;
    // Namespacing events
    $('.some-elem').on('click.my_event', function(){
      alert("Div is clicked!");
    });
    
    // Unbind namespaced event
    $('.some-elem').unbind('click.my_event');
  2. Use function reference when binding and unbinding.
    // User function reference
    var my_func = function(){
      alert("Div is clicked!");
    };
    
    // Bind using function reference
    $('.some-elem').on('click', my_func);
    
    // Unbind namespaced event
    $('.some-elem').unbind('click', my_func);

Caching in jQuery

What is great about jQuery is its simplicity in selecting elements. We all use it here and there, basically everywhere. This simplicity comes with its drawbacks. jQuery traverses through all elements every time we use selectors. So to boost up your jQuery application you should always cache your selections to some variable (if you find yourself using the same selection more than once). In case you are not selecting an element more than once you should not cache your selection by assigning it to some variable.

Here is an example:
var cached = $('.someElement'); 
cached.addClass('cached-element');
Here are the performance tests:
console.time('test'); 
for (i = 0; i < 1000; i++) { 
    $('.the').text(i + ' '); 
} 
console.timeEnd('test'); 
// ~260ms 

console.time('test2'); 
var the = $('.the'); 
for (i = 0; i < 1000; i++) { 
    the.text(i + ' '); 
} 
console.timeEnd('test2'); 
// ~30ms

As you can see caching increased performance by nearly 10 times.

How to test JavaScript code performance

Sometimes after all day long coding your code becomes not so effective and your code (usually interface related) becomes slow. You have done so many changes and don't exactly know what slowing it down. In cases like this (and of course, plenty other cases) you can test your JavaScript code performance.  First of all, you need Firefox browser and Firebug web developers life saver plugin. I can not think of my web programming work without it.

Anyway, Firebug makes available console variable to your JavaScript page. Console can be used for logging or printing out debugging information to the Firebug console. Console also has one handy method for tracking time in milliseconds.

console.time('timerName');

// Your javascript code to test here 

console.timeEnd('timerName');

You can use this script to test your JavaScript code. timerName in the code can be any name for your timer. Don't forget to end your timer using the same name for timeEnd().

Everything is an Object in JavaScript

The title maybe a little misleading. So don’t confuse things like Arrays, RegEx, Boolean, etc. with Object! They are all obejcts but a different class. They have common and non-common methods. You can use jQuery's $.type() method to check any given variable's class.

Most of the time we work with arrays or arrays like jQuery objects. So jQuery has built-in method to check if a variable is an array ($.isArray(var)).

var bool = true;
var arr = [];
var int = 10;

$.type(bool); // "boolean"
$.type(arr);  // "array"
$.type(int);  // "number"

Now, back to our initial statement: "Everything is an Object". This means that integers, floats and booleans, etc. also behave like ordinary objects. Which in turn means that we can add and call properties on them as well. Let's see an example:

var bool = true;
var arr = [];
var int = 10;

bool.foo = "bar";          // no syntax error
arr['bar'] = function(){}; // still not an error
int[bool] = "error?";      // nope - not an error

Because everything is an object, JavaScript engine will allow this property assignment methods. However, it will ignore the assignments and when called it will return "undefined". Number class objects are an exception.

bool.foo;  // undefined
arr['bar'] // undefined
int[bool]  // undefined

var obj = new Number(); 
obj.name = "My Name"; 
console.log(obj["name"]); // "My Name"

So, knowing this little fact helps you understand why for in loops, for example, allow itirating over arrays. By the way, array keys are internally implemented as object properties. Also, array's .length property is also not an exception, but a simple property defined on an array object.

var array = [];
array.length;      // 0
array[1] = "bar";
array.length;      // 2

Since Functions are first class citizens, you can add properties to your functions as well. That's pretty cool.

function myFunk(){ 
    this.name = "My Name"; 
} 

var obj = new myFunk(); 
obj.newProperty = "Dynamicly Created"; 
obj.newMethod = function(){ return "Hello"; } 

alert( obj["newMethod"]() );

The most important feature is an ability to dynamically created new properties and methods.

TIP:
In case you want your methods to be available to all class instances assign them as a property for .prototype.

What a heck is a (function ($){ ... })(jQuery)

Recently I wrote two articles on how to extend jQuery using its plug in system and a shorthand for that. If you look into them closely they are actually the same thing. The only difference being that the code in first one is wrapped in this anonymous JavaScript function:

(function ($) { 
    // code goes here 
})(jQuery)

Little research shows that this allows the use of $ within this function without conflicting with other JavaScript libraries who are using it. Basically, since we are setting $ as  a parameter, $ will overwrite any globally defined variables/references of $ in that particular anonymous function.

// Assume "$" is a prototype reference 
(function ($) { 
    // Here "$" is a jQuery reference 
})(jQuery)

So basically it’s an anonymous function that lets jQuery play nicely with other javascript libraries that might have $ variable/function. Also if you notice, all jQuery plugins code is wrapped in this anonymous function.

NOTE:
The following two javascript codes are equivalent:

// Code 1:
(function ($) { 
    // Javascript code 
})(jQuery)

// Code 2:
var myFunction = function ($) { 
    // Javascript code 
};
myFuntion(jQuery);