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 comment:1
Changed December 15, 2010 03:43PM UTC by 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 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 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 comment:5
resolution: | → duplicate |
---|---|
status: | new → closed |
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
, orbody
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'sbody
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
).