views:

335

answers:

7

I always wondered why jQuery returns true if I'm trying to find elements by id selector that doesnt exist in the DOM structure.

Like this:

<div id="one">one</div>

<script>
    console.log( !!$('#one') ) // prints true
    console.log( !!$('#two') ) // is also true! (empty jQuery object)
    console.log( !!document.getElementById('two') ) // prints false
</script>

I know I can use !!$('#two').length since length === 0 if the object is empty, but it seems logical to me that a selector would return the element if found, otherwise null (like the native document.getElementById does).

F.ex, this logic can't be done in jQuery:

var div = $('#two') || $('<div id="two"></div>');

Wouldnt it be more logical if the ID selector returned null if not found?

anyone?

+6  A: 

This is just how jQuery works.

$("#something")

Object 0=div#something length=1 jquery=1.2.6

$("#nothing")

Object length=0 jquery=1.2.6

Balon
+3  A: 

You can come close to doing what you want by accessing the length the element, and combine with the ternary operator:

console.log(!!$('#notfound').length);  // false
console.log(!!$('#exists').length);    // true
var element= $('#notfound').length ? $('#notfound') : $('#exists');
console.log(element.attr('id'));  // outputs 'exists'

As to the heart of the question:

Wouldnt it be more logical if the ID selector returned null if not found?

No, not for the JQuery way of doing things - namely, to support chaining of JQuery statements:

    $('#notfound').hide("slow", function(){
      jQuery(this)
        .addClass("done")
        .find("span")
          .addClass("done")
        .end()
        .show("slow", function(){
          jQuery(this).removeClass("done");
        });
    });

Even though notfound doesn't exist this code will run without stopping script execution. If the initial selector returns null, you'll have to add in an if/then block to check for the null. If the addClass, find, end and show methods return null, you'll have to add an if/then block to check the return status of each. Chaining is an excellent way to handle program flow in a dynamically typed language like Javascript.

pygorex1
+1  A: 

You could check the .length property of the jQuery object. Like this:

if($("#two").length > 0) { // exists...

} else { // doesn't exist

}
vrutberg
That's a nice one. It can actually yet be shortened: `if ($("#two").length)` should do the trick as well.
miek
+16  A: 

This behaviour was chosen because otherwise jQuery would regularly throw NullReference Exceptions

Almost all jQuery functions return a jQuery object as a wrapper around the Dom elements in question, so you can use dot notation.

$("#balloon").css({"color":"red"});

Now imagine $("#balloon") returned null. That means that $("#balloon").css({"color":"red"}); would throw an error, rather than silently doing nothing as you would normally want.

Hence, you just gotta use .length or .size()

Dan
I was also thinking this was one of the reasons. But is it really a good idea to suppress errors this way? If the id is not found, I'd sure like to know where the error is thrown instead of debugging each chain.
David
This might be the behaviour you'd want if you are using the id selector, as ids are (normally) unique. But what if you were using a class selector, to close all dialogs/popups on a page. You wouldn't want the function to throw an error just because the user didn't happen to have any dialogs currently open. You'd want it to silently do nothing.
Dan
JavaScript does not have anything called NullReference Exceptions. Perhaps you mean `ReferenceError`?
Tim Down
A: 

In short, you could think of the jQuery selector return value as a group containing 0..n elements, but never being null.

What you're probably really interested in is $("#two")[0], which will give you the first actual element returned by the selector.

miek
`$("#two:first")` will still return a jQuery object.
J-P
Thanks J-P, I stand corrected. Updated the answer.
miek
+1  A: 

It returns true because to Javascript it is a defined object therefore not false. However there are no elements in the pseudo array, e.g.

$("#id")[0]

You can write your own plugin to avoid repeated if statements as a Jquery plugin, like I did for this one. It's fairly easy to do:

(function($)
{
        /* Checks if a jQuery object exists in the DOM, by checking the length of its child elements. */
        $.fn.elementExists = function()
        {
                ///     <summary>
                ///     Checks if a jQuery object exists in the DOM, by checking the length of its child elements.
                ///     </summary>
                ///     <returns type="Boolean" />
                return jQuery(this).length > 0;
        };
})(jQuery);

Usage:

if ($("#someid").elementExists())
{

}
Chris S
A: 

To detect whether jquery object is null or not: http://praveenbattula.blogspot.com/2010/01/how-to-check-jquery-object-is-null.html

Rare Solutions