4 jQuery Cross-Domain AJAX Request methods

The web has changed and with it the way we develop websites. Today, the web is becoming a place where we develop web apps, rather than websites. We use third party API's to create our next mashups. So knowing how to make a cross-site AJAX request or requests that do not comply with the same origin policy is a must. In this article, you will learn 4 cross-site AJAX request methods (plus 4 bonus legacy methods and links to jQuery plugins).

This methods will be handy to overcome Same origin policy as well. Browsers will throw an error if you are making AJAX request to the same domain but with different protocol (to https from http), use different port (http://same-domain.com:81) or subdomain.

This article reviews the following 4 methods and discusses their advantages & disadvantages. Also, summarise cases when they are better used.

Here is the list of methods:

  1. CORS (Cross-Origin Resource Sharing)
  2. JSONP
  3. window.postMessage
  4. Setting up a local proxy
  5. + 4 bonus legacy methods (document.domain, window.name, iframe, flash)
  6. + list of JavaScript libraries and jQuery plugins for making XSS requests.

Before we dive into the method details, let's cover most common cases:

  • Firstly, if you are trying to read data that is available as RSS feed, you are better off with universal RSS to JSON converter powered by Google.
  • Secondly, if you are accessing data from some popular website API, it's more likely they support JSONP as well. See their documentation.

JSONP is a cross browser method that does not rely on any browser hacks. It is supported by all browsers and many javascript libraries provide methods that make JSONP request seamless.

jQuery: How many elements were selected

Anyone who used jQuery, starts with a CSS selector to either attach an event or apply some DOM manipulation. The power of jQuery lies in it’s CSS selector. One of the reasons why jQuery become so popular is probably in the concept shift it made to front-end development. Instead of starting your code with javascript function definitions, you start with DOM element selection and straight to your business requirements manipulating those elements. It abstracted away the problems of code structure and let you get on with your needs by selecting the objects you need.

Sometimes your code might require to identify how many elements were selected by jQuery. It might be to identify if there are any elements on the page or to use the number of elements in some other way. For example to set rowspan on your newly created table row. In this post, you will learn how to find out how many elements were selected and see some examples.

jQuery selector returns an array of elements jQuery object that has .length attribute. So the easiest way is to get the length of returned jQuery object. The size of that object will be equal to the number of selected elements. Also, you can use built in jQuery helper function called .size(). It returns the same value as .length property. So you can use .length or .size() depending on your choice, whichever makes your code more readable.

Examples

Assume we have the following HTML structure:

<div class="container">
  <div class="item">Item 1</div>
  <div class="item">Item 2</div>
</div>

Here is how you get the number of selected elements and check if there are any elements on the page.

  1. Check the number of elements:

    $('.container').length;  // returns 1
    $('.item').length;       // returns 2
    
    // Same with .size()
    $('.container').size();  // returns 1
    $('.item').size();       // returns 2
  2. Check if there are any elements:

    if($('.container').size() > 0) {
      // There is an element with class "container"
    } else {
      // There is no element with class "container"
    }

Let's see another example. Consider we have the following mark-up for a shopping cart with several order lines in it.

<div class="shopping-cart">
  <div class="order-line">Product 1 – <span>$4.99</span></div>
  <div class="order-line">Product 2 – <span>$9.99</span></div>
</div>

Business requirement: Show a modal box with special offer, if user has more than 1 products in his/her shopping cart.

if($('.shopping-cart .order-line').length > 1) {
  // Show modal box with special offer
}

jQuery: Add table row count column

In this post you will learn how to add a table column with a row count in it. If you are looking for "how to add a new table row", please refer to previous post.

Recently, a user on the jQuery mailing list asked how she could automatically add a table row counter into her table. She wanted to add a new column to her table and display the row number, so that her users could refer to row numbers while communicating. The user had the following HTML table markup:

<table class="transactions">
  <tr>
    <td>Order 1</td>
    <td>$10.99</td>
  </tr>
  <tr>
    <td>Order 2</td>
    <td>$4.50</td>
  </tr>
</table>

For cases like this, where you can be sure that there would be no table cell rowspans and there are only trs and tds. Then, jQuery code to add a counter is straightforward.

$('.transactions tr td:first-child').each(function(i){
  $(this).before('<td>'+(i+1)+'</td>');
});

Here, we are selecting first child td tags of all tr tags in a table with a transactions class. Then, we are iterating through them and passing a zero based index to the loop. While looping though the first row cells, we are adding new column just using .before('<td>'+(i+1)+'</td>') method. The resulting table would have the following markup:

<table class="transactions">
  <tr>
    <td>1</td>
    <td>Order 1</td>
    <td>$10.99</td>
  </tr>
  <tr>
    <td>2</td>
    <td>Order 2</td>
    <td>$4.50</td>
  </tr>
</table>

However, for cases when tables have header rows and footer, the above script may not behave as expected. That is why we have to take into the consideration table headers and footers. So the code snippet above will become:

$(".transactions").each(function(){
  $('th:first-child, thead td:first-child', this).each(function(){
    var tag = $(this).prop('tagName');
    $(this).before('<'+tag+'>#</'+tag+'>');
  });
  $('td:first-child', this).each(function(i){
    $(this).before('<td>'+(i+1)+'</td>');
  });
});

This code takes into the account the table headers and adds "#" header column for the counter. Still, this code is not as universal as it could have been. Let’s take into the account the possibility of row spans and multi line header rows and rewrite the code into the jQuery plugin with options.

So, here is the final code:

(function($){
  $.fn.extend({
    tableAddCounter: function(options) {
      
      // set up default options 
      var defaults = { 
        title:  '#',
        start:  1,
        id:     false, 
        class:  false,
      };

      // Overwrite default options with user provided
      var options = $.extend({}, defaults, options);

      return $(this).each(function(){
        // Make sure this is a table tag
        if($(this).is('table')){

          // Add column title unless set to 'false'
          if(!options.title) options.title = '';
          $('th:first-child, thead td:first-child', this).each(function(){
            var tagName = $(this).prop('tagName');
            $(this).before('<'+tagName+' rowspan="'+$('thead tr').length+'" class="'+options.class+'" id="'+options.id+'">'+options.title+'</'+tagName+'>');
          });
        
          // Add counter starting counter from 'start'
          $('tbody td:first-child', this).each(function(i){
            $(this).before('<td>' + (options.start + i) + '</td>');
          });
        
        }
      });
    }
  });
})(jQuery);

Plugin features

  • Can set custom settings as a hash parameter to the plugin:
    • title - counter column header text
    • start - the number to start the counter
    • id - CSS "id" to add to all the counter tds
    • class - CSS "class" to add to all the counter tds
  • It takes into consideration table header's row and column spans.
  • Gracefully degrade for browsers that do not support javascript.
  • Keeps your HTML mark up clean.
  • Make your tabular data more readable.

Example code

// Add row count with default settings
$('.myTables').tableAddCounter(); 

// Provide your settings for 
// column name, css class and start counter from 26
var options = { 
  name: "Count", 
  class: "counter",
  start: 26
};
$('.myTables').tableAddCounter(options);

Here is the original table (to the left) and new table (to the right) with row columns automatically added.

tableAddCounter jQuery plugin screenshot

5 notes on JavaScript Arrays

In this post, we will go through some of the features of JavaScript's Arrays. I thought this would be a good place to come back time to time and refresh my memory about special cases and notes I've collected on Arrays in Javascript. Without futher ado, 5 notes on JavaScript Arrays.

1. Arrays are Objects in JavaScript

Arrays are Objects in JavaScript. Let me repeat it one more time: "Arrays are Objects". Understanding this helped me simplify my conceptual understanding of the language. Instead of rembembering different special cases and syntax for Arrays and Objects, now, we just need to remember rules to work with Objects alone.

Now, let me elaborate on it more. Array index keys are just property names of an object. Since, a property name can not start with a number, we have to use alternative [''] property access notation just like we would with any other object. So, there is nothing special about Array keys. They are just object property names that are integers.

var array = [1, 2, 'three', 4, 5]; // or 'new Array()'

array.0    // SyntaxError: Unexpected number
array[0]   // 1
array[2]   // 'three'

2. Arrays keys are String

Internaly javascript engine keeps array keys as String values, because naming rules do not allow properties starting with a numeral. When you access array values with an integer, javascript engine casts it into string. So this means that JavaScript Arrays are not breaking any of the naming rules defined by the language. Property names are not starting with an integer and they are stored as strings. Let's see some examples.

var array = [1, 2, 'three', 4, 5];

array[1]                 // 2
array['1']               // 2 - Accessing with a string works just fine
array['3'] == array[3]   // 'true'
array['03'] == array[3]  // 'false' - because array['03'] != array['3']
array['03'] == array[03] // 'false'

In the example above: array['03'] is not equal to array[03], because numerical value 03 furst turned into 3 and only then casted into string. So the end equation would become array['03'] == array[3] and that equals to false.

3. Arrays keys must be positive integers

Just like in any other programming language, JavaScript imposes a rule that array keys can only be positive integers. You can still treat them as if they were objects and set values to any keys. Javascript engine would simply ignore them.

var array = [1, 2, 'three', 4, 5];

array['06'] = 7;
array['str'] = 'some value';
array.prop = 'another value';

console.log( array );  // [1, 2, 'three', 4, 5]

array['6'] = 7;
console.log( array );  // [1, 2, 'three', 4, 5, undefined, 7]

4. Use the literals notation [] instead of new Array()

The new Array() is ambiguous in how it deals with its parameters, so it is better to always use alternative [] notation to define arrays. The literals are more readable and shorter as well.

You can read more about this behaviour here.

// Prefered method
var array = [1, 2, 'three', 4, 5];

// Not so prefered
var array2 = new Array(5);

5. Loop through arrays with for() loop

As we said previously, arrays are objects. So you can loop through them using for in loop. But it is not recommended. Because, for in loops through all the properties that are in the prototype chain and you will have to use .hasOwnProperty() check. This means only 2 things:

  1. bloated and hard to read code;
  2. performance penalty.
var array = [];
a[1000] = 'some value';

for (key in array) {
  if (a.hasOwnProperty(key)) {
    array[key]; // 'some value'
  }
}

// Recommended
for(var index = 0, l = array.length; index < l; index++) {
  array[index]; // 'some value'
}

// OR if you have ECMAScript5 support
array.forEach(function(value) {
    value; 'some value'
});

6. Bonus notes

Since arrays are objects of an Array class. We can check if an object is an array.

function is(type, obj) {
  var clas = Object.prototype.toString.call(obj).slice(8, -1);
  return obj !== undefined && obj !== null && clas === type;
}

is('Array', [1, 2, 3]); // true

If you have jQuery included on your page, use either $.type() or $.isArray().

var array = [1, 2, 3];

$.type(array);     // 'array' - string
$.isArray(array);  //  true   - boolean