The enduring popularity of this question on Stackoverflow: How to do this using jQuery – document.getElementById(“selectlist”).value took me back to the very first issue I had with jQuery. Namely:

Why on earth does $(“myid”) not give me the DOM object for “myid” like document.getElementById(“myid”)?

In fact it gives you a collection of all elements <myid> which for this is almost certain to be empty.

But no-one explains this to you. No-one takes you aside and says, “listen, forget the DOM, forget all its functions, pretend it never existed…this is all DIFFERENT”…or something.

This is the first thing you should know about jQuery. Everything else is trivial.

As I intimated in my answer $() and document.getElementbyId are “Equivalent”.

Being in the right place at the right time to answer this question was fortunate, and was the Stackoverflow equivalent of a Jackpot if you care about your reputation points. Here is the answer I gave, and how it looks after four revisions:

While…

$('#selectlist').val();

…is equivalent to…

document.getElementById("selectlist").value

…it’s worth noting that…

$('#selectlist')

…although ‘equivalent’ is not the same as…

document.getElementById("selectlist")

…as the former returns a jQuery object, not a DOM object.

To get the DOM object(s) from the jQuery one, use the following:

$('#selectlist').get(); //get all DOM objects in the jQuery collection
$('#selectlist').get(0); //get the DOM object in the jQuery collection at index 0
$('#selectlist')[0]; //get the DOM objects in the jQuery collection at index 0

It should also be noted that the return from $() is a collection, and may contain MANY items. If you are selecting by ID (using #) then you will only ever get one item

, , ,
Example DOM Tree
Image via Wikipedia

jQuery does a wonderful job of traversing the DOM tree, so you might ask why you would like to do this yourself?
I recently encountered a requirement to count the maximum ‘depth’ of a DOM tree. I.e. find the level of the deepest nested element. So, I managed to knock this up in a few minutes:

function Recurse($item, depth) {
    $item.each(function() {
        depth.count++;
        if (depth.count > depth.max) {
            depth.max = depth.count;
        }
        Recurse($(this).children(), depth);
    });
    depth.count--;
    return depth.max;
}

$(document).ready(function() {
    alert(Recurse($("body"), { count: 0, max:0 }));
}

A few points to note about this

  • depth is an object with two members, count and max. We want to keep a count of the current and maximum depth, but want to avoid global variables (it’s better practice, and makes the solution more self-contained).
  • JavaScript doesn’t allow us to pass variables by reference. Using the variables within the passed depth object means we can pass values to lower levels of recursion.
  • We must pass an object in our first call. Technically the function can be improved by including a check for this.
  • The function returns depth.max. Although the return value doesn’t matter when the function is called recursively, its useful for passing our intended value out to the original calling function.

You can test this out on JsFiddle: http://jsfiddle.net/RqHzf/

Enhanced by Zemanta
,

Have you ever found yourself wanting to test out a bit of HTML/CSS/JavaScript without having access to an IDE or being bothered to fire it up?

Do you want to hack prototype a bit of code quickly without fuss?

Or maybe you’re one of those StackOverflow answerers that Race To Get The First Answer In.

If your answer is ‘yes’ or ‘I am actually’ then there’s probably a myriad of different resources you can call upon to help out, but you might consider JSFiddle

I created  a really simple bit of code:

HTML

<input type="checkbox" />

JavaScript/jQuery

$("input").click(function(){alert("test");});

Then I selected ‘jQuery 1.4.2.’ from the ‘Choose Framework’ section and clicked run.

When I clicked on the checkbox, everything hung together like a dream:

At the time of writing the blurb stated that it was still under heavy development, however I still thought it was a genuinely nice little tool that I wanted to share.

Enhanced by Zemanta
, , , ,

Last year I held a jQuery course, and was fortunate enough to recieve very generous praise from my peers, including the following:

What parts of the training did you feel were of most value?Biscuits
The overview of the key paragdim interjected with real examples expedited learning

What parts of the training did you feel were of least value?
The lack of biscuits

What, if anything, would you change about the course?
Provide biscuits

Any further comments?
More biscuits please

So there we have it. Biscuits, cakes, muffins, coffees and teas. Bribing your audience can always help!

, ,

Back in September 2008 Microsoft announced that it would be shipping jQuery with Visual Studio going forward. This was pretty momentous news at the time, as noted in the jQuery Blog.

True to its word, Microsoft Shipped jQuery with Visual Studio 2010, and it is now included by default in your ASP.NET web projects.

Further to this, Microsoft is now actively contributing to the jQuery project itself.

All this really underlines the emerging dominance of jQuery and gives extra reason for this to be JavaScript library of choice for anyone thinking of adopting a JavaScript framework.

,

Synopsys

Use chaining as an alternative to variable caching and multiple selector calls.

Where chaining is used, appropriate line breaks and indentation should be used.

Do not over-chain. For long chains it acceptable to cache intermediate objects in a variable.

Description

Chaining is one of the signature features of jQuery. Used correctly, it can reduce the amount of code we have to write and the amount of data that is held in memory.

Chaining can be considered as an alternative to:

  • Caching jQuery objects in local variables
  • Performing multiple selections

Where chaining is used, appropriate line breaks and indentation should be used.

When to Use Chains

Chains should not compromise the readability of the code. For long chains, finding and defining a formatting and indentation strategy can be troublesome.

It can be better in these instances to cache your jQuery object in a separate variable.

When a JavaScript object is cached in jQuery, the reference to the object is actually stored. This occupies a minimal amount of memory, leaving negligible performance degradation.

The items show some indentation strategies, and a representation with a cached variable:

Chain Formatting Examples

Long Chains – Indentation Strategy 1

$("#MyTable").append(
    objButton.parents("tr").clone()
        .find(".RowTitle")
            .text("Row " + String(AddCount)).end()
        .find(".MySelect1")
            .attr("id", "SomeId" + String(AddCount))
                .change(function() { ChangeFundRow() }).end()
        .find(".MySelect2")
            .attr("id", "SomeOtherId" + String(AddCount)).end()
);

Long Chains – Indentation Strategy 2

$("#FundTable").append(
    objButton
        .parents("tr")
            .clone()
                .find(".RowTitle")
            .text("Row " + String(AddCount))
            .end()
                .find(".MySelect1")
                .attr("id", "SomeId" + String(AddCount))
                .change(function() {
                    ChangeFundRow();
                })
            .end()
                .find(".MySelect2")
                .attr("id", "SomeOtherId" + String(AddCount))
            .end()
);

To the untrained eye, either of the above may take some deciphering. In this case, a better strategy could be to cache your selections in a separate variable:

Long Chains – Caching Variable

var $clonedRow = objButton.parents("tr").clone();
$clonedRow.find(".RowTitle")
          .text("Row " + nAddCount); 

$clonedRow.find(".MySelect1")
    .attr("id", "FundManager" + nAddCount)
    .change( ChangeFundRow ); 

$clonedRow.find(".MySelect2")
          .attr("id", "FundName" + nAddCount); 

$clonedRow.appendTo("#FundTable");

jQuery Coding Standards Menu

  1. jQuery Variables
  2. DOM Manipulation
  3. Events
  4. Page Style and Layout Changes
  5. Effects and Animation
  6. Selectors
  7. Plugins
  8. Chaining
, ,

Synopsis

Do not reinvent the wheel. Use plugins if they fit your functional requirement.

Ensure the plugins are fit-for-purpos, well regarded and well tested.

Description

Plugins are a way by which any developer can extend the jQuery library. They are often useful, frequently well tested and supported, and may well cut down on development time.

The following are some commonly used plugins:

Reviewing Plugins for Use

The review process for including a plugin should encompass some sort of investigation into the plugin itself. The following aspects should be examined:

  • The current level of use I.e. is it widely adopted? Those with a large number of users will be well tested and developed.
  • For which version of jQuery was it written? Is it still valid for your current version of jQuery?
  • The current level of support. E.g. does it have a website with examples, etc. An example of one with good support is BlockUI (http://malsup.com/jquery/block/#)
  • Quality of plugin comments – A quick scan of the code will see if it’s well documented. If its well documented, then it should be well written.
  • How well is it regarded?. A quick internet search across the jQuery community and its users should reveal this.
  • Availability of vsdoc js for intellisense. Not critical, but would be a factor in choosing two plugins that were identical to each other in every other aspect.

Writing Plugins

Whenever you find yourself developing some jQuery that could be considered generic, and could certainly adopted within other areas of the code base, then you should consider turning it into the jQuery plugin.

The ‘how’ of doing this is outside the scope of these standards. Refer to jQuery literature (department books and online) for how to do this. Experienced jQuery developers may also be able to assist.

As a starting point, any plugin should begin with the following closure code convention:

    function($){
        //plugin code
    }(jQuery);

jQuery Coding Standards Menu

  1. jQuery Variables
  2. DOM Manipulation
  3. Events
  4. Page Style and Layout Changes
  5. Effects and Animation
  6. Selectors
  7. Plugins
  8. Chaining
, ,

Synopsis

Use #ID selector wherever possible. It is the fastest.

Ensure slower selectors are optimised for performance – Combine them with faster selectors where possible.

Custom selectors must be kept simple, as they may end up being run upon every element in the DOM.

Avoid needless selector combinations.

Description

Selectors are ranked by performance as follows:

  1. #Id
  2. Element
  3. .class, :pseudoclass and :custom

The Class and PseudoClass and Custom selectors are slower than ID and Element selectors. The deficiency of their performance can be mitigated by combining them with other selector types, so do this wherever possible.

Examples

    $(".oddRows");                   //Inefficient: scans DOM for all elements with oddrows class
    $("tr.oddRows");                 //More efficient: Searches only <tr>s with oddrows class
    $("#MyTable tr.oddRows");        //More efficient: searches descendents of #MyTable
    $("#MyTable>tbody>tr.oddRows");  //Best: searches immediate children

In these examples, we have combined CSS style selectors to obtain better performance in two ways:

  • Element.WithClass – I.e. search for element with the specified class name
  • #Id Descendents – I.e. search within descendents of the Id.
  • #Id>Children – I.e. search only immediate children

The optimisation of selector performance is essential for efficient jQuery. This must be a major consideration for developers and code-reviewers alike.

Custom Selectors

It is possible within jQuery to define custom selectors, as per the following example:

    $.extend($.expr[":"], {
        textboxEmpty: function(el) {
            return $(el).val() === "";  //must return boolean
        }
});
alert($(":text:textboxEmpty").length);

Custom selectors must be kept simple, as they may end up being run upon every element in the DOM.

Be aware that Custom and Pseudoclass selectors are, at best, as slow as class selectors (complex custom selectors may be even be slower!). Therefore you should attempt to optimise their performance by utilising some of the techniques described above.

For a tutorial on writing custom selectors, check out my blog post here.

Pitfalls and Traps

Assuming Children and Descendants

The example “#MyTable>tbody>tr.oddRows” helps us demonstrates the potential pitfalls of assuming specific children/descendants. Had we written this as “#MyTable>tr.oddRows” then our selector would have returned nothing!

Correct Use of Parent-Child

The selector $(“#MyTable .oddRows”) will return all elements in the DOM with the oddrows class assigned (there is a space between #MyTable and .oddRows)

However, the selector $(“#MyTable.oddRows”) will probably return nothing, as the code imples that we are looking for the table with the Id #MyTable that has the class oddrows assigned to it.

Given the naming convention in the example it seems unlikely that that the table will have the class assigned.

Needless Selector Combinations

The Id of an element should be unique. Therefore there is no need to combine it with other selectors. For example, the selector $(“#MyTable.TableClass”) is probably pointless as the query for #MyTable will already have returned at most one element.

In the same vein, the selector $(“div #MyTable”) is also pointless. Here we are going to select all divs in the DOM, and then scan that subsection for #MyTable.

Defining an Id at the start of a Parent-Child selector can, however improve selector performance greatly, and is strongly encouraged. See selector performance examples above.

jQuery Coding Standards Menu

  1. jQuery Variables
  2. DOM Manipulation
  3. Events
  4. Page Style and Layout Changes
  5. Effects and Animation
  6. Selectors
  7. Plugins
  8. Chaining
, ,