Skip to main content

Bug Tracker

Side navigation

#7784 closed bug (duplicate)

Opened December 15, 2010 03:46AM UTC

Closed December 15, 2010 08:18PM UTC

Last modified December 15, 2010 08:19PM UTC

$(str) is failing when str is an entire html document

Reported by: cowboy Owned by:
Priority: undecided Milestone: 1.6
Component: unfiled Version: 1.4.4
Keywords: Cc:
Blocked by: Blocking:
Description

Go to jquery.com, and enter this into the console. You'll see that while the html string is being logged, $(html) is not acting as expected, stripping the html, head and body tags and flattening the structure somewhat. As a result, $(html).find('body') returns nothing!

$.get( '/', function( html ){
  console.log( html ); // full html string, as-expected
  console.log( $(html) ); // html, head, body removed?
  console.log( $(html).find('body') ); // nothing ?!
});

Another example for the jquery.com console:

$('<div/>').load( '/', function(){
  console.log( this );
});

logs this:

<div>​
  <meta http-equiv=​"content-type" content=​"text/​html;​ charset=utf-8">​
  <title>​jQuery: The Write Less, Do More, JavaScript Library​</title>​
  <link rel=​"stylesheet" href=​"http:​/​/​static.jquery.com/​files/​rocker/​css/​reset.css" type=​"text/​css">​
  <link rel=​"stylesheet" href=​"http:​/​/​static.jquery.com/​files/​rocker/​css/​screen.css" type=​"text/​css">​
  <link rel=​"alternate" type=​"application/​rss+xml" title=​"jQuery Blog" href=​"http:​/​/​jquery.com/​blog/​feed/​">​
  <link rel=​"shortcut icon" href=​"http:​/​/​static.jquery.com/​favicon.ico" type=​"image/​x-icon">​
  <div id=​"jq-siteContain">​…​</div>​
  <!-- /#siteContain -->
</div>​

And this:

$('<div/>').load( '/ body', function(){
  console.log( $(this).html() );
});

logs nothing!

Attachments (0)
Change History (6)

Changed December 15, 2010 03:25PM UTC by cowboy comment:1

FWIW, I have been operating under the impression that the whole point of $.fn.load was to be able to load (and select from) entire html documents, as per the examples at http://api.jquery.com/load/.

Placing this seemingly arbitrary restriction that a developer can't target the html, head, or body elements of deserialized entire-html-document strings in $(str) or $.fn.load isn't great.

Of course, I'm sure it's not actually arbitrary, it only ''seems'' arbitrary to me as I try to do the following:

A common use case for $.fn.load might be to very quickly "ajaxify" a site by "hijacking" internal links with a delegated click handler, loading the target page's html via GET request and then replacing the existing body's contents with the newly loaded page's body contents.

So perhaps this use-case isn't as common as I thought, because it doesn't work!

Maybe this is an issue of documentation. Maybe it can be fixed without too much effort. Either way, the current behavior doesn't feel particularly elegant, requiring someone who just wants to quickly "ajaxify" a site to wrap all their ajax-loaded content in a parent element (that's ''not'' body).

Changed December 15, 2010 03:43PM UTC by dmethvin comment:2

Maybe this is an issue of documentation.

You mean documentation like this? :)

jQuery uses the browser's .innerHTML property to parse the retrieved document and insert it into the current document. During this process, browsers often filter elements from the document such as <html>, <title>, or <head> elements. As a result, the elements retrieved by .load() may not be exactly the same as if the document were retrieved directly by the browser. http://api.jquery.com/load/

I agree it would be ideal if we could somehow load complete document HTML (somewhere off the current document, without fetching its linked images/css) and inject just parts of them into the current document. There are some workarounds like loading the doc into an iframe or fetching it as an XML document, but they have their own sets of problems and don't work for the general case either.

See also #7757 .

Changed December 15, 2010 03:55PM UTC by cowboy comment:3

Also, given this test.html:

<!DOCTYPE HTML>
<html lang="en-US">
<head>
  <title>Index page</title>
</head>
<body>
  <div id="content">
    <p>stuff</p>
    <p>more stuff</p>
  </div>
</body>
</html>

If I do this:

$('<div/>').load( 'test.html #content', function(){
  console.log( this );
} );

I get this, which should be expected:

<div>​
  <div id=​"content" class=​"content">​…​</div>​
</div>​

Bit if I use $.get instead of using $.fn.load plus a string selector, this (extremely unintuitive) behavior is what I observe:

$.get( 'test.html', function(html){
  console.log( $(html).find( '#content') ); // fails!
  console.log( $(html).filter( '#content') ); // works!
});

Of course, this works.. but it's also fairly inelegant:

$.get( 'test.html', function(html){
  console.log( $('<div/>').html( html ).find( '#content' ) ); // ugleey!
});

Changed December 15, 2010 04:11PM UTC by cowboy comment:4

_comment0: A user could do something like this, however: \ \ {{{ \ $.get( 'test.html', function(html){ \ html = html.replace( /<(\\/?)(html|head|body)([^>]*)>/g, function(a,b,c,d){ \ return '<' + b + 'div' + ( b ? '' : ' data-element="' + c + '"' ) + d + '>'; \ }); \ \ // These all behave as-expected: \ console.log( $( html ).find( '#content' ) ); \ console.log( $( html ).find( '[data-element=head]' ).children() ); \ console.log( $( html ).find( '[data-element=body]' ).contents() ); \ }); \ }}}1292429819145596

A user could do something like this, however:

$.get( 'test.html', function(html){
  html = html.replace( /<(\\/?)(html|head|body)([^>]*)>/ig, function(a,b,c,d){
    return '<' + b + 'div' + ( b ? '' : ' data-element="' + c + '"' ) + d + '>';
  });
  
  // These all behave as-expected:
  console.log( $( html ).find( '#content' ) );
  console.log( $( html ).find( '[data-element=head]' ).children() );
  console.log( $( html ).find( '[data-element=body]' ).contents() );
});

Changed December 15, 2010 08:18PM UTC by snover comment:5

resolution: → duplicate
status: newclosed

Changed December 15, 2010 08:19PM UTC by snover comment:6

Duplicate of #3409.