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);

How to add custom jQuery functions

In this post you will learn how to add your own custom functions to jQuery. In essence, this is the same as creating jQuery plugin. Recently I wrote a template on how to extend jQuery and how to create your own functions. Since then I came across even smaller code snippet on how to add your own custom functions, in other words how to create plugins for jQuery.

So without further ado:

$.fn.myFunction = function() { 
  return $(this).addClass('changed');
}

// Now, you can use it like this
$('.changePlease').myFunction();

Even though, it is a shorter version, you are better off using the correct way. The correct way is to wrap your custom function code into the closure so that it does not interfere with surrounding code and does not cause issues with redefining existing variables.

Defining custom jQuery functions

(function($){

  $.fn.extend({
    myFunction: function() {
      return $(this).addClass('changed');
    }
  });

})(jQuery);

// OR equivalent

(function($){

  $.fn.myFunction = function() {
    return $(this).addClass('changed');
  }

})(jQuery);

By using the above recommended methods of creating custom jQuery functions, we are making sure that:

  1. We do not assume that jQuery is not in jQuery.noConflict() mode. So our code does not require that $ refers to jQuery.
  2. We can define custom variables without worrying about polluting global namespace. Since our code is defined in the closure, our variables will not overwrite global variables. Overwriting global variables may cause unexplainable unit test failures and unidentifiable bugs.

The two methods are technically the same. The $.fn.extend() method is basically merging our passed object with itself. Whereas, in the $.fn.custom_method = case we are explicitly defining property on the $.fn object. So in the essence, jQuery allows adding custom function by defining properties on $.fn object.

This means that we are not limited to custom functions, but also can define custom variables as well. It can be used as a global property holder. This properties are accessible from anywhere on in your code. So plugins can use it to exchange data between themselves.

Defining custom jQuery variables/properties

(function($){

  $.fn.extend({
    my_data: {
      version: "0.1",
      author:  "Author Name",
      url:     "http://www.example.com"
    }
  });

})(jQuery);

// OR equivalent

(function($){

  $.fn.my_data = {
    version: "0.1",
    author:  "Author Name",
    url:     "http://www.example.com"
  }

})(jQuery);

Now you can accesses it from anywhere where jQuery is accessible. That includes other jQuery plugins, custom functions and custom code.

console.log( $().my_data );

// Outputs
{ version: "0.1", author: "Author Name", url: "http://www.example.com" }

// Usage
document.location = $().my_data.url;

We can define new properties on $.fn, but it is better to define them on $ itself. Having said that, it is better namespace your data like it is showen in the example belove.

(function($){

  $.myApp = {
    version: "0.1",
    author:  "Author Name",
    url:     "http://www.example.com",
  }

})(jQuery);

// Usage
$.myApp.author;  // "Author Name"

Google hosted jQuery

Formerly Google AJAX API, now Google hosted libraries is a content delivery network (CDN) for several popular JavaScript libraries. The CDN provides reliable, high-speed, high-availability and global access to files hosted on it.

UPDATE:
You can also use jQuery hosted by Microsoft CDN servers.

If you are using one of the libraries belowe, Google has you covered:

  • AngularJS
  • Chrome Frame
  • Dojo
  • Ext Core
  • jQuery & jQuery UI
  • MooTools
  • Prototype
  • script_aculo_us
  • SWFObject
  • Web Font Loader

As you can see, Google CDN also hosts jQuery (as well as jQuery UI). In this post we will concentrate on jQuery.

Google CDN hosts uncompressed as well as minimized jQuery files, supports gzip. The main advantage of using Google hosted jQuery is that if your visitors have already visited some site that loaded jQuery from Google servers, then it would already be on user's machine. So the browser would load it from its' cache.

Today, almost everyone is using Google hosted jQuery. So there is a huge chance that your visitors have it cached. By using Google CDN, you are reducing your page load times.

Here is how to load jQuery from Google servers:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js" type="text/javascript"></script>

At the time of writing, Google hosts the following versions of jQuery:

2.0.3, 2.0.2, 2.0.1, 2.0.0,
1.10.2, 1.10.1, 1.10.0,
1.9.1, 1.9.0,
1.8.3, 1.8.2, 1.8.1, 1.8.0,
1.7.2, 1.7.1, 1.7.0,
1.6.4, 1.6.3, 1.6.2, 1.6.1, 1.6.0,
1.5.2, 1.5.1, 1.5.0,
1.4.4, 1.4.3, 1.4.2, 1.4.1, 1.4.0,
1.3.2, 1.3.1, 1.3.0,
1.2.6, 1.2.3

You can see up to date versions of hosted jQuery versions on Google Developers page.

Legacy method: Loading jQuery using Google AJAX API

Up until jQuery version 1.7.2, Google had javascript library loader API. If your legacy project is already using it to load other libraries, here is how you can use it to load jQuery.

<script src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
  google.load("jquery", "1.7.2");
  google.setOnLoadCallback(function() {
    // Your code goes here.
  });
</script>

Loading jQuery UI from Google CDN servers

Google CDN also hosts jQuery UI files. So if you are using jQuery UI you can also load it using these links and code:

<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js" type="text/javascript"></script>

<!-- OR Legacy method -->

<script src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
  google.load("jquery", "1.3.2");
  google.load("jqueryui", "1.7.2");
  google.setOnLoadCallback(function() {
    // Your code goes here.
  });
</script>

Currently Google hosts these versions of jQuery UI library:

1.10.3, 1.10.2, 1.10.1, 1.10.0,1.9.2, 1.9.1, 1.9.0,
1.8.24, 1.8.23, 1.8.22, 1.8.21, 1.8.20, 1.8.19, 1.8.18, 1.8.17, 1.8.16,
1.8.15, 1.8.14, 1.8.13, 1.8.12, 1.8.11, 1.8.10, 1.8.9, 1.8.8, 1.8.7, 1.8.6,
1.8.5, 1.8.4, 1.8.2, 1.8.1, 1.8.0, 1.7.3, 1.7.2, 1.7.1, 1.7.0, 1.6.0, 1.5.3, 1.5.2

How to create a jQuery plugin, extending jQuery the easy way

One of the reasons jQuery is so popular is the number and quality of its' plugins. They allow quickly achieve user goals and get on with their lifes. A lot of tasks can be done by jQuery plugins without ever have to write any custom jQuery code.

However, when you write some awesome code and think the community will benefit from it - release it as jQuery plugin. In this post, you will learn how to extend jQuery with your custom plugins.

jQuery: Bind events to AJAX loaded / dynamically created elements

One of the most used features of jQuery is DOM manipulation, but right after that are probably event binding and AJAX content loading. When we bind events to AJAX loaded or dynamically added elements our app might not behave as we would have expected. This is one of the oldest dilemmas of front-end development.

jQuery has addressed this problem back in version 1.3 by introducing .live() method. Since then, the jQuery team has improved upon it and introduced .delegate() and .on() event binding methods. Depending on the jQuery version your project is using, you will need to use one of these methods.

In this post, I will try to help you identify the recommended way of binding events to AJAX loaded (or dynamically created) elements depending on jQuery version you are using. Also, cover some of the performance considerations you should be aware of.

Access to restricted URI denied" code: "1012

This post will discuss and provide several solutions to "Access to restricted URI denied" error. This error is thrown in Firefox browser, while making AJAX request that does not comply with the browser's security policies.

The error occurs when application tries to do an AJAX request that does not comply with the same-origin policy or tries to access a local resource (file on your hard drive with a path like file://c:/Users/etc.). To solve this problem you need to change the URI to your files so that it appears as if they were on the same domain as the page your AJAX script is calling it from.

Let's try to reproduce the error.

$(document).ready(function(){

  // Try to load content from the hard drive
  $.get('file:///Users/path-to/seed-data.js', function(data){
    console.log(data);
  });

  // Try to load content from another domain
  $.ajax({
    url: "http://www.google.com/some-file.html",
  }).done(function(data) {
    console.log(data);
  });

  // Try to load content from the same domain, but different protocol
  // Assume we are on http://www.example.com page and trying to access
  // page on the same secure domain "https"
  $.get('https://www.example.com/seed-data.js', function(data){
    console.log(data);
  });

});

The examples above will result in the following error in your JavaScript console.

Access to restricted URI denied" code: "1012
xhr.open(type, s.url, s.async);

Reasons

  1. In the first example, the reason for the error is Firefox's security model that does not allow retrieving/accessing resources localhost resources.

  2. In the second example, Firefox enforced "same origin" security policy that does not allow accessing resources from other domains (NOTE: www.example.com and example.com are considered two different domains as well).

  3. In the third example, we tried to access resources using different protocol (https). Don't forget HTTP and HTTPS are two different protocols.

Solutions

In order to solve the "Access to restricted URI denied" error, you need to identify which of the reasons above is causing your script to throw an error and fix it with one of the solutions below.

  1. First problem: Deploy files to a web server or alternatively run one locally (ex. XAMPP). Once deployed, access your page from your domain (http://www.your-domain.com/page.html or http://localhost:port/page.html).

  2. To access resources from other domains you have to overcome the "same origin policy". This can be done by putting a simple proxy script on your own domain and it would appear as if you are fetching resources from your own domain. You can find description and an example proxy script in “Cross domain AJAX scripting” post.

  3. The solution to the last method is usually easy. In most cases it is either putting or removing "s" to/from "http". But for cases when you have to grab content from URL using different protocol, your only solution is to use proxy script described in the second solution.

If this post does not cover your case please leave a comment with reproducable code or a link to fiddle page. If you found this post helpful, please share/like it.