Because DataTables is built on JQuery, at some point you're going to need to know a little JQuery to solve the challenges of getting your DataTables running. This blog post hopes to familiarize you with the basics to get you up and running quickly.
What is JQuery?
JQuery is a library of functions created by developers who wanted functionality or convenience that they did not find in Javascript. Because JQuery is not directly part of Javascript you need to include a file with the JQuery library so that your code can use the library and it's objects. A JQuery object is an object that comes with a lot of great functions from the JQuery library. It is usually wrapped around a DOM element (an object representing an HTML tag in a web document). $('#example') returns a JQuery object wrapped around whichever DOM element has the id "example", this is used often in the DataTables usage examples where there is a <TABLE> tag with id="example".
The JQuery object is not the DOM element itself, but just has a pointer or reference to it. Standard Javascript functions or member names used on DOM elements won't work so instead use the functions provided by the JQuery library to provide the same functionality.
// standard Javascript
var obj = document.getElementById('example');
var objid = obj.id;
var objhtml = obj.innerHTML;
// JQuery equivalent
var $obj = $('#example');
var objid = $obj.attr("id"); // get "id" attribute
var objhtml = $obj.html();
var obj = document.getElementById('example');
var objid = obj.id;
var objhtml = obj.innerHTML;
// JQuery equivalent
var $obj = $('#example');
var objid = $obj.attr("id"); // get "id" attribute
var objhtml = $obj.html();
How can I tell between DOM and JQuery?
If you can't treat a JQuery object the same as a DOM object, how can you tell the difference? Here's a little trick: DOM objects don't have a length defined. JQuery objects can act as an array of elements (because your selector might return more than one element) and has length defined. You can also adopt a naming convention that makes your JQuery objects more obvious to the reader.. you might notice I named my JQuery object $obj, with a dollar sign.
// detect undefined length. if defined, your obj is not a DOM element
if (typeof obj.length !== "undefined") { ... }
// if you want to ignore DOM elements and JQuery objects with 0 length
if (obj.length) { ... }
if (typeof obj.length !== "undefined") { ... }
// if you want to ignore DOM elements and JQuery objects with 0 length
if (obj.length) { ... }
If you have a JQuery object (which usually represents a collection of 0 or more DOM elements) you can get a DOM element by referencing a numeric index as if JQuery is an array. And if you have a DOM element, you can use the JQuery function to wrap a JQuery object around it
var obj = $obj[0]; // get the first DOM element in $obj
var $obj = $(obj); // get the first DOM element in $obj
var $obj = $(obj); // get the first DOM element in $obj
What has JQuery done for me lately?
I think if JQuery just provided it's "selector" power, that would be enough to make it worthwhile, but it provides much more. The "selector" magic I'm talking about is the definition you provide that tells JQuery which objects you are interested in. JQuery combines the best of css class names, tag names, id values, and several other features and combines them with relationship operators to help you find the specific elements you want. And it's a lot less typing than .getElementById().
JQuery has some great documentation found at JQuery Selectors reference, but here are a few of the most common selectors you should learn:
$t = $('table'); // selects all elements with html tag "table"
$u = $('.red'); // selects all elements with css class "red"
$v = $('#example'); // selects all elements (should only be 1 if you use unique id) with id "example"
$tr = $('table#example tr'); // select all tr elements that are descendants of table element with id "example"
$tr = $('tr', $t); // select all tr elements that are descendants of our $t variable
$td = $('#example > td'); // select all td elements that are direct children of element with id example (probably none because TD's are usually inside TR elements which might be inside THEAD or TBODY or TFOOT elements)
$td = $('#example td:eq(0)'); // returns the first TD element in element with id "example"
$td = $('#example td:first'); // same as above, using :first selector
$td = $('#example tbody > tr:first :first-child'); // probably the same TD - the first child of the first TR element in the TBODY
$u = $('.red'); // selects all elements with css class "red"
$v = $('#example'); // selects all elements (should only be 1 if you use unique id) with id "example"
$tr = $('table#example tr'); // select all tr elements that are descendants of table element with id "example"
$tr = $('tr', $t); // select all tr elements that are descendants of our $t variable
$td = $('#example > td'); // select all td elements that are direct children of element with id example (probably none because TD's are usually inside TR elements which might be inside THEAD or TBODY or TFOOT elements)
$td = $('#example td:eq(0)'); // returns the first TD element in element with id "example"
$td = $('#example td:first'); // same as above, using :first selector
$td = $('#example tbody > tr:first :first-child'); // probably the same TD - the first child of the first TR element in the TBODY
There are tons more - check out the documentation.
Not only does JQuery provide powerful selectors, but you can perform operations on the returned JQuery object. Some of the operations further select elements, and some allow you to process the values in the collection held by the JQuery object. Here are some more selector-type functions
$td = $('#example tbody').find('td:first'); // yet another way to narrow down values.. same as $('#example td:first'); and $('td:first', '#example'); but convenient if you already have a JQuery object like $t in a variable.
$t.children(); // return a new JQuery object with all children of $t
$t.children('td'); // return a new JQuery object with all TD children of $t
$t.parent(); // return parent node of $t
$t.children(); // return a new JQuery object with all children of $t
$t.children('td'); // return a new JQuery object with all TD children of $t
$t.parent(); // return parent node of $t
To get/set the innerHTML or value or any other HTML attribute of elements in a jquery object, use:
$('#example tbody').find('td:first').html('<a href="http://www.blogger.com/link.php">My link</a>');
$t.children('input:text').val(''); // clear all the textboxes that are inside $t
$t.html(); // return the innerHTML for the whole table.
$('#example tbody').find('input:text :last').attr('value'); // same as $('#example tbody').find('input:text :last').val();
$t.children('input:text').val(''); // clear all the textboxes that are inside $t
$t.html(); // return the innerHTML for the whole table.
$('#example tbody').find('input:text :last').attr('value'); // same as $('#example tbody').find('input:text :last').val();
Event Planner
In the same way that JQuery's selectors provide an easier way to select DOM elements, JQuery provides an improved interface for attaching event listeners to DOM elements (or creating your own triggered events and listeners). Because of the browser wars and some browsers not complying to standards, it can be a mess to attach event listeners using Javascript to target all the browsers and their quirks - with JQuery, the library does all that for you so you have a single interface to attaching events.
// the javascript way to target Firefox/Chrome on one hand and IE on the other
if (elem.addEventListener) elem.addEventListener (eventType,handler,false); // FF and standard browsers likes this
else if (elem.attachEvent) elem.attachEvent ('on'+eventType,handler); // IE likes this
// JQuery simplifies this
$(elem).bind(eventType, handler);
// most of the normal events have their own function for convenience
$(elem).click(handler); // same as $(elem).bind("click", handler);
if (elem.addEventListener) elem.addEventListener (eventType,handler,false); // FF and standard browsers likes this
else if (elem.attachEvent) elem.attachEvent ('on'+eventType,handler); // IE likes this
// JQuery simplifies this
$(elem).bind(eventType, handler);
// most of the normal events have their own function for convenience
$(elem).click(handler); // same as $(elem).bind("click", handler);
Live wire
The best thing about JQuery's event handling, especially in DataTables where rows and cells go in and out of memory, is the .live() event function. If you use .live(), any matching elements will have the event handler added to them, even if they are created after you set up the handler. It is exactly like bind except it continuously monitors for any new elements.
$('td').live("click", handler); // will add handler to any td elements, even if they are created in the future, i.e. after DataTables redraws the table
Chain gang
The authors of JQuery designed their library so that every selector function can accept a previously made JQuery object, and that every selector function returns a JQuery object. This way, you can run multiple operations on the same set of DOM elements in a JQuery object by chaining them together. (The return object isn't always the same set as was passed to it - .find() returns elements that are children of the original set, for example.) This constraint encourages people to write code that is modular and can fit in with any other plug-ins.
$('#example').dataTables().find('tbody td').html('hi').value('hello').length; // the .length helps show this is a JQuery object
// this is the same as:
$t = $('#example');
$u = $t.dataTables(); // yes, as a plug-in function, dataTables also returns a JQuery object (we'll talk more later about this)
$v = $u.find('tbody td'); // now we have a different set of items, but still inside a JQuery object
$w = $v.html('hi'); // when you GET .html() or .val() it returns primitive values like strings, but when you SET, it returns a JQuery object after performing the action. this one sets the innerHTML for all TD elements in TBODY to 'hi'
$x = $w.val('hello'); // set VALUE attribute to 'hello';
$x.length; // remember this? JQuery objects have length, which helps to demonstrate that they are JQuery objects
// this is the same as:
$t = $('#example');
$u = $t.dataTables(); // yes, as a plug-in function, dataTables also returns a JQuery object (we'll talk more later about this)
$v = $u.find('tbody td'); // now we have a different set of items, but still inside a JQuery object
$w = $v.html('hi'); // when you GET .html() or .val() it returns primitive values like strings, but when you SET, it returns a JQuery object after performing the action. this one sets the innerHTML for all TD elements in TBODY to 'hi'
$x = $w.val('hello'); // set VALUE attribute to 'hello';
$x.length; // remember this? JQuery objects have length, which helps to demonstrate that they are JQuery objects
DataTables is a JQuery object?
Yup. DataTables, as a system, is a JQuery object with all the JQuery functions available to it; DataTables also adds quite a few functions to JQuery, and although they might not make sense in a context other than a DataTable object these functions exist for any JQuery object (they will likely halt your program, though because they expect the object to have specific parts set up as they would be if you called the .dataTable() function, and the .dataTable() function expects a TABLE element that includes a THEAD and TBODY element, etc.).
All the extension functions you write (if you write plugins for DataTables) are really functions that will be added to the JQuery library/instance on your page. However, DataTables passes it's oSettings object as the first parameter to API functions, so I don't think you can write your functions to be chainable - and I don't think that's a big deal. You could, though, write API functions that return JQuery objects. Then your function's return value can be used to start a chain of functionality.
If you aren't writing plugins, you can still benefit because you can pass $oTables (or oSettings.oInstance, or $('#example').dataTables().fnSettings().oInstance) to any function that will accept a JQuery object.
Had enough yet?
Feel free to ask questions for clarification, or make corrections if I've made errors, or to get some insight into topics I haven't covered or only briefly touched on.
This comment has been removed by a blog administrator.
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDeleteTo the "event planner" and "live wire" sections, I would also add a section on using .delegate(). The delegate() event binding utility creates fewer and more efficient listeners.
ReplyDeleteWithout researching the technicalities, let's imagine (whether fully accurate or not) that .live just uses the body element as the listener. The difference with .delegate is that you need to specify a listener that will check for events on a matching selector within that listener.
$('td').live("click", handler); // the example
becomes
$('#wrapper').delegate('td', 'click', handler);
Where #wrapper is the closest common ancestor of the TDs in question. You also need to pick an ancestor that isn't going to be destroyed during other DOM manipulation (for example, using '.dataTable_wrapper table' is not a good choice because many uses of DT involve destroying and replacing the table).
Interesting one. Keep posting such kind of information on your blog. I bookmarked it for continuous visit.
ReplyDeletehtml5 video player