tags:

views:

159

answers:

2

I'd like some help with the following jQuery code if possible...

 $(document).ready(function() {
  $('table.sortable').each(function() {
   var $table = $(this);
    $('th', $table).each(function(column) { // #A
     var $header = $(this); 
      $header.click(function() {
       var rows = $table.find('tbody > tr').get();
        rows.sort(function(a, b) { // #B
         var keyA = $(a).children('td').eq(column).text().toUpperCase(); //#C
         var keyB = $(b).children('td').eq(column).text().toUpperCase();
          if(keyA < keyB) return -1;
          if(keyA > keyB) return 1;
          return 0;
          });
          $.each(rows, function(index, row) { //#D
           $table.children('tbody').append(row);
          });
        });
     });
   });
 });

For the comments I've added (#A through to #D), can somebody explain to me:

#A - What signifies the closure/end of this function... i.e. where does the function end? I'm naively looking for a closing curly brace, otherwise from reading the code I'm assuming the whole body of code is run for each 'th' element encountered, which doesn't seem very efficient? Does one of the "});"'s at the end signify the end of this function?

#B - I would love to understand how this comparator function works. My book covers it really briefly and I can't find any other resources on the web! What values will be passed into the function via the arguments 'a' and 'b'? Can somebody painstakingly explain this whole function, please?! :)

#C - How does the .eq(column) part work? I would assume that if 'column' contains the iteration the loop is currently on, the value will always be the final iteration value? Or does this comparator function run for each iteration through the .each loop?

#D - This function presumably goes through each row of the sorted array rows and appends it to the table body. Are these two arguments (index, row) always included in the $.each callback function?

Any help gratefully received!! I already have an answer for #B, if you could just help by answering one of the queries, I will show my appreciation with upvotes! Thanks in advance.

+1  A: 

To answer #B: the rows.sort() takes a function with two parameters (a and b in this case) and return a value to indicate what is the relationship between the two for the sort. In short it is a comparator that will tell the sorting algorithm whether a comes before b or after it. In this invocation a and b will be two rows of the table and the text form the relevant cell (indicated by column) will be used after it is converted to upper case.

mfloryan
+1  A: 

I've marked up the code signifying the end of each function you asked about. (see code at the end of post).

#A: It looks like to code was optimized for size, not speed. Functions usually should not be created inside other functions. Also, $table.find('th') may be faster than $('th', $table) and there are some other small optimizations that could be performed.

mfx answered #B

#C: "column" here relates to the position in the nodeList/array (jQuery object). So yes, it is the iteration jQuery's "each" loop is on. jQuery's "each" function uses javascript's native "call" function kinda like this (simplified):

function each(jQueryObject, callback){
    for(var index in jQueryObject){
        singleEach(jQueryObject[index], index, callback);
    }
}
function singleEach(singleObject, currentIndex, callback){
    // singleObject = "this" & currentIndex = "column" in your case
    // function.call(object, argument1, argument2, argument3..., argument_n)
    callback.call(singleObject, currentIndex, singleObject);
}
each(["one","two","three"], function(i, myObject){
    // alerts the current index and the current indexes value.
    // myObject === this.
    alert(i + "= " + this);
});

So every time each() performs one iteration (singleEach) the current index is passed as an argument to the callback function which is called within its own scope.
The iteration only runs when a heading column is clicked and NOT for each iteration of the each loop.

#D yup they sure are! If you look at the function singleEach you can see that it passes two arguments to the callback function. The first is the index and the other is the object itself (this).

    $table.children('tbody').append(row);

could be written as:

    $table.children('tbody').append(this);

You should take a look at the jQuery code yourself and the jQuery documentation.


$(document).ready(function() {
    $('table.sortable').each(function() {
        var $table = $(this);
        $('th', $table).each(function(column) { // #A
            var $header = $(this); 
            $header.click(function() {
                var rows = $table.find('tbody > tr').get();
                rows.sort(function(a, b) { // #B
                    var keyA = $(a).children('td').eq(column).text().toUpperCase(); //#C
                    var keyB = $(b).children('td').eq(column).text().toUpperCase();
                    if(keyA < keyB) return -1;
                    if(keyA > keyB) return 1;
                    return 0;
                }); // end of B
                $.each(rows, function(index, row) { // #D
                    $table.children('tbody').append(row);
                }); // end of D
            });
        }); // end of A
    });
});
David Murdoch