Rudiger W.
Rudiger W.

Reputation: 868

jquery.html() returns only first text when loaded from string

Supposedly a jquery object can be initialized from string. This can often happen when processing ajax results, i.e. I'm trying to replicate http://api.jquery.com/jQuery.post/

However, I'm seeing strange behavior:

function test() {
    var content = $("<html><body><div>hello</div><div>world</div></body></html>");
    alert("content.text() = " + content.text());
    alert("content.html() = " + content.html());
}

The first alert shows: content.text() = helloworld

The second alert shows: content.html() = hello

What's happening here?

Solution

Thanks everyone for the explanations. I ended up adding another layer of <div> to have a single child of <body>, as in

<html>
 <body>
  <div>    <=== added
   <div>hello</div>
   <div>world</div>
  </div>
 </body>
</html>

Upvotes: 6

Views: 1739

Answers (3)

Ram
Ram

Reputation: 144689

Browsers remove those html and body elements. The content collection has only 2 div elements.

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.

This is the string representation of your content collection:

content.map(function() { return this.outerHTML || this.nodeValue; }).get().join('');
// -> <div>hello</div><div>world</div>

.text() method returns textContent/nodeValue of all the elements in the collection:

content.text(); // -> helloworld

.and .html() method returns innerHTML of the first element in the collection:

content.html(); // -> hello

Upvotes: 1

unconditional
unconditional

Reputation: 7656

This is what your content looks like to a browser:

"content = " Object { 0: <div>, 1: <div>, length: 2 }

Basically this is in some kind a set of 2 elements.

And here's what http://api.jquery.com/html/ say:

Get the HTML contents of the first element in the set of matched elements

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1074495

When parsing HTML fragments containing a body element, browsers in general (and jQuery does this as well) will disregard everything except what's inside the body element. So what you have there ends up being equivalent to:

var content = $("<div>hello</div><div>world</div>");
alert("content.text() = " + content.text());
alert("content.html() = " + content.html());

You end up with a jQuery object with two elements in it: The div elements.

In jQuery, normally accessor functions (html, val, css, etc.) only use the first element in the set when you use them as getters, and that's what html is doing above. text is an unusual accessor function in jQuery: It gives you the combined text of all of the elements in the set, not just the first.

We can see this in the docs, but it's still surprising. From html:

Get the HTML contents of the first element in the set of matched elements or set the HTML contents of every matched element.

From text:

Get the combined text contents of each element in the set of matched elements, including their descendants, or set the text contents of the matched elements.

(My emphasis in both cases.)

Upvotes: 1

Related Questions