elaich
elaich

Reputation: 941

What find() exactly returns?

I was testing a method with qunit, and i found something i didn't understand.

The function is checking if all descendants of are scanned, i used a variable to calculate the number of occurrences.

test ("all body children highlilighted", function(){
        var body = $('<body><form><label>This is a label</label><input type="text" /></form><input type="text" /></body>') ;
        scan_body(body) ;

        var compteur = 0 ;

        body.find('*').each(function(idx, val){
                var past_color = $(this).css('background-color') ;
                var present_color = $(this).mouseenter().css('background-color') ;
                notEqual(past_color, present_color, "We expected the color of this element to be changed") ;
                compteur++ ;
        }) ;
        equal(compteur, 5, "5 expected !!!!") ;
}) ;

the final assertion is always false, compteur contains 2 always. Why ?

Upvotes: 0

Views: 87

Answers (2)

kamituel
kamituel

Reputation: 35960

The behaviour you're experiencing is because jQuery's $(), when used to parse HTML string, uses innerHTML internally (putting your HTML into a <div>). It is explained in jQuery documentation:

When passing in complex HTML, some browsers may not generate a DOM that exactly replicates the HTML source provided. As mentioned, jQuery uses the browser"s .innerHTML property to parse the passed HTML and insert it into the current document. During this process, some browsers filter out certain elements such as <html>, <title>, or <head> elements. As a result, the elements inserted may not be representative of the original string passed

And innerHTML strips out <body> if you try to put it into a <div> (JSFiddle):

var div = document.createElement('div');
div.innerHTML = '<body><form></form></body>';
// div == <div><form></form></div>

If not for this, you would see compteur equal to 4, as per @T.J. Crowder answer.

Upvotes: 2

T.J. Crowder
T.J. Crowder

Reputation: 1074969

(I'm assuming you're using jQuery.)

This happens because the body tag is treated specially for some reason: What we're getting back isn't a body element, it's a form element and only has what's in the form (the label and the input). If you replace body with div, you'll get the expected result, which is 4 (not 5; find only finds descendants, so the top-level element wouldn't be counted).

I'm surprised to find body being treated specially, but that is what's happening.

This version using body, with irrelevant bits commented out, shows that what we get back is only the form and its contents (I added ids to the inputs so we could tell them apart):

function foo(){
    var body = $('<body><form><label>This is a label</label><input id="first" type="text" /></form><input id="second" type="text" /></body>') ;
    //scan_body(body) ;

    var compteur = 0 ;

    console.log("<code>body[0].tagName</code>: " + body[0].tagName);        
    body.find('*').each(function(idx, val){
        //var past_color = $(this).css('background-color') ;
        //var present_color = $(this).mouseenter().css('background-color') ;
        //notEqual(past_color, present_color, "We expected the color of this element to be changed") ;
        console.log(
          idx + ": " +
          this.tagName + 
          " (" + (this.id || "[no id]") +
          ")");
        compteur++ ;
    }) ;
    console.log("compteur = " + compteur);
}
foo();

Live Copy

Result:

Using body
body[0].tagName: FORM
0: LABEL ([no id])
1: INPUT (first)
compteur = 2

But the exact same thing using div gives us the expected results (the div with all of the content) - Live Copy:

Using div
body[0].tagName: DIV
0: FORM ([no id])
1: LABEL ([no id])
2: INPUT (first)
3: INPUT (second)
compteur = 4

Upvotes: 2

Related Questions