Reputation: 28564
I've been trying to GET a HTML file and assign it to a variable as a jQuery object. To no avail. I'm not sure if Stack Snippets allow GET requests, so here is a JSFiddle link as well.
var html = '<!DOCTYPE html><html lang="en"><head><title>Template</title></head><body itemscope itemtype="http://schema.org/WebPage"><main><header itemscope itemtype="http://schema.org/Country" itemprop="about"><h1 itemprop="name">Dummy heading</h1><p><span class="capital" title="Capital" itemprop="containsPlace"></span><span title="Dummy title" itemprop="additionalProperty" itemscope itemtype="http://schema.org/PropertyValue"><meta itemprop="name" content="Member of the EU since"><span itemprop="value" class="member-since">Dummy year</span></span></p></header><div itemprop="mainEntity" itemscope itemtype="http://schema.org/ItemList"><meta itemprop="description" content=""><article class="recipe loading" itemprop="itemListElement" itemscope itemtype="http://schema.org/Recipe"><meta itemprop="position" content=""><aside class="media"><div class="img-gallery" itemscope itemtype="http://schema.org/ImageGallery"></div><div itemscope itemtype="http://schema.org/VideoObject" class="youtube"><a itemprop="contentUrl" href="#" title=""><meta itemprop="name" content=""><meta itemprop="uploadDate" content=""><meta itemprop="description" content=""><img itemprop="thumbnailUrl" src="#" alt=""></a><div class="youtube-player"></div></div></aside><div class="text"><div class="wiki-text"><h1 itemprop="name">Dummy heading</h1><p itemprop="description"></p><p class="read-more">For more information about <span class="recipe-name"></span>, read the <a href="#" title="" itemprop="sameAs">Wiki</a>.</p></div><div class="rating" itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating">Rated <span itemprop="ratingValue">3.5</span>/5 based on <span itemprop="reviewCount">11</span> customer reviews</div><div class="cooking"><h2>Bake it yourself!</h2><div><meta itemprop="cookTime" content=""><span>Bake time: <span class="bake-time"></span></span></div><div class="ingredients-wrapper"><h3>Ingredients <small>for <span itemprop="recipeYield"></span></small></h3><div class="ingredients"><h4>Dummy heading</h4><ul></ul></div></div><div class="how-to"><h3>Steps</h3><ol></ol></div></div></div></article></div></main></body></html>';
$.ajax({
type: 'post',
url: "/echo/html/",
dataType: "html",
data: {
html: html,
delay: 1
}
}).done(function(data) {
// string
console.log(data);
// array
console.log($(data));
// array
console.log($.parseHTML(data));
// array
console.log($($.parseHTML(data)));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
The HTML is valid. Yet, I can't get it in an object. The returned data is, as expected, a string. But when I try to parse that string as HTML using $.parseHTML()
or putting it in a jQuery selector $()
or even try both I always get the same result: an array containing the title and main element.
So some way some how jQuery still parses it and makes an array of the element in the head and the one element in the body. But why? And how can I remedy this, and transform it into a jQuery object? I am only interested in the contents of the body.
There is a similar question, but the accepted solution doesn't help as it goes into JSFiddle and I'm also experiencing this problem locally with XAMPP.
Upvotes: 3
Views: 863
Reputation: 90287
document.querySelector("body").innerHTML = +
'<object type="text/html" data="'+html+'" ></object>';
...just works. So I'd have expected:
let parsedHtml = $('<object />', {
type:'text/html',
data:html
}).html()
to also just work, But I'm guessing some magic happens when one actually adds it to DOM. It parses it, builds CSSOM and DOM for it and loads all dependencies, basically what you'd expect a browser to do with an .html
resource.
So here's a way to do it:
<object>
inside, .contents()
of <object>
(on it's onload
event), let html = '// your valid html...',
dummyDiv = $('<div />',{
html: '<object type="text/html" data="'+html+'" ></object>',
style:"height:0;overflow:hidden;"
});
$('html').append(dummyDiv);
console.log(dummyDiv.find('object').contents());
Note Chrome is already smart enough to detect a display:none
on a parent and not load the <object>
. That's why I used height:0;overflow:hidden;
. You will notice the contents of this element doesn't have a typical stucture of a jQuery object, because it's a document. you'll find the juice in
dummyDiv.find('object').contents()[1].innerHTML
When the html string is already in a variable, it loads instantly, but in reality you'll need to place an onload
listener on the <object>
and only run 4. and 5. when the listener triggers.
Upvotes: 2
Reputation: 387
I always get the same result: an array containing the title and main element.
What exactly is the problem?
jQuery still parses it and makes an array of the element in the head and the one element in the body. But why?
What are you expecting?
That seems to be the behavior of parseHtml.
Here's another example:
$.parseHTML("<div>Hello<span>World</span></div>")
It returns an array with one element: div
If you look at the docs for parseHTML it says:
Parses a string into an array of DOM nodes.
So it seems to be doing exactly what it's supposed to.
I am only interested in the contents of the body.
The content of the body is main
which as you have noted is the second element.
What do you want to do with it?
You can wrap it in a jQuery object by passing it to the jQuery constructor.
var html = '<!DOCTYPE html><html lang="en"><head><title>Template</title></head><body itemscope itemtype="http://schema.org/WebPage"><main><header itemscope itemtype="http://schema.org/Country" itemprop="about"><h1 itemprop="name">Dummy heading</h1><p><span class="capital" title="Capital" itemprop="containsPlace"></span><span title="Dummy title" itemprop="additionalProperty" itemscope itemtype="http://schema.org/PropertyValue"><meta itemprop="name" content="Member of the EU since"><span itemprop="value" class="member-since">Dummy year</span></span></p></header><div itemprop="mainEntity" itemscope itemtype="http://schema.org/ItemList"><meta itemprop="description" content=""><article class="recipe loading" itemprop="itemListElement" itemscope itemtype="http://schema.org/Recipe"><meta itemprop="position" content=""><aside class="media"><div class="img-gallery" itemscope itemtype="http://schema.org/ImageGallery"></div><div itemscope itemtype="http://schema.org/VideoObject" class="youtube"><a itemprop="contentUrl" href="#" title=""><meta itemprop="name" content=""><meta itemprop="uploadDate" content=""><meta itemprop="description" content=""><img itemprop="thumbnailUrl" src="#" alt=""></a><div class="youtube-player"></div></div></aside><div class="text"><div class="wiki-text"><h1 itemprop="name">Dummy heading</h1><p itemprop="description"></p><p class="read-more">For more information about <span class="recipe-name"></span>, read the <a href="#" title="" itemprop="sameAs">Wiki</a>.</p></div><div class="rating" itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating">Rated <span itemprop="ratingValue">3.5</span>/5 based on <span itemprop="reviewCount">11</span> customer reviews</div><div class="cooking"><h2>Bake it yourself!</h2><div><meta itemprop="cookTime" content=""><span>Bake time: <span class="bake-time"></span></span></div><div class="ingredients-wrapper"><h3>Ingredients <small>for <span itemprop="recipeYield"></span></small></h3><div class="ingredients"><h4>Dummy heading</h4><ul></ul></div></div><div class="how-to"><h3>Steps</h3><ol></ol></div></div></div></article></div></main></body></html>';
var parsed = $.parseHTML(html)
var main = parsed[1]
var $main = $(main)
// $main is a jQuery object
console.log("h4 content:", $main.find('h4').text())
Upvotes: 0
Reputation: 61
Problem is you are trying to access direct html but actually its a string.
So you have to render html to access data.
For that store response data into any html element and access through it.
I changed your jsfiddle
so you can see.
Upvotes: 0
Reputation: 1
Set jQuery.ajax()
processData
option to false
. Use DOMParser()
to parse string to an html
document
; XMLSerizlizer()
to get DOCTYPE
declaration; document.write()
to write DOCTYPE
and parsed document
.documentElement.outerHTML
to current or other html
document
.
processData (default:
true
)Type: Boolean
By default, data passed in to the
data
option as an object (technically, anything other than a string) will be processed and transformed into a query string, fitting to the default content-type "application/x-www-form-urlencoded". If you want to send a DOMDocument, or other non-processed data, set this option tofalse
.
I'm not sure if Stack Snippets allow GET requests
Yes. It is possible to echo GET
request by setting url
to data URI
or Blob URL
representation of resource at $.ajax()
, XMLHttpRequest()
or fetch()
, see Does Stack Overflow have an “echo page” to test AJAX requests, inside a code snippet?
var html = `<!DOCTYPE html>
<html lang="en">
<head>
<title>Template</title>
</head>
<body itemscope itemtype="http://schema.org/WebPage">
<main>
<header itemscope itemtype="http://schema.org/Country" itemprop="about">
<h1 itemprop="name">Dummy heading</h1>
<p><span class="capital" title="Capital" itemprop="containsPlace"></span><span title="Dummy title" itemprop="additionalProperty" itemscope itemtype="http://schema.org/PropertyValue"><meta itemprop="name" content="Member of the EU since"><span itemprop="value" class="member-since">Dummy year</span></span>
</p>
</header>
<div itemprop="mainEntity" itemscope itemtype="http://schema.org/ItemList">
<meta itemprop="description" content="">
<article class="recipe loading" itemprop="itemListElement" itemscope itemtype="http://schema.org/Recipe">
<meta itemprop="position" content="">
<aside class="media">
<div class="img-gallery" itemscope itemtype="http://schema.org/ImageGallery"></div>
<div itemscope itemtype="http://schema.org/VideoObject" class="youtube">
<a itemprop="contentUrl" href="#" title="">
<meta itemprop="name" content="">
<meta itemprop="uploadDate" content="">
<meta itemprop="description" content=""><img itemprop="thumbnailUrl" src="#" alt=""></a>
<div class="youtube-player"></div>
</div>
</aside>
<div class="text">
<div class="wiki-text">
<h1 itemprop="name">Dummy heading</h1>
<p itemprop="description"></p>
<p class="read-more">For more information about <span class="recipe-name"></span>, read the <a href="#" title="" itemprop="sameAs">Wiki</a>.</p>
</div>
<div class="rating" itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating">Rated <span itemprop="ratingValue">3.5</span>/5 based on <span itemprop="reviewCount">11</span> customer reviews</div>
<div class="cooking">
<h2>Bake it yourself!</h2>
<div>
<meta itemprop="cookTime" content=""><span>Bake time: <span class="bake-time"></span></span>
</div>
<div class="ingredients-wrapper">
<h3>Ingredients <small>for <span itemprop="recipeYield"></span></small></h3>
<div class="ingredients">
<h4>Dummy heading</h4>
<ul></ul>
</div>
</div>
<div class="how-to">
<h3>Steps</h3>
<ol></ol>
</div>
</div>
</div>
</article>
</div>
</main>
</body>
</html>`;
$.ajax({
type: "GET",
url: "data:text/html," + html,
processData: false
})
.then(function(data) {
// string
console.log(data);
var parser = new DOMParser();
// document
var d = parser.parseFromString(data, "text/html");
// `document`, `document` as jQuery object
console.log(d, $(d));
// get elements having `itemscope` attribute
console.log($(d).find("[itemscope]"));
// do stuff
var dt = new XMLSerializer().serializeToString(d.doctype);
document.write(dt, d.documentElement.outerHTML);
})
.fail(function(jqxhr, textStatus, errorThrown) {
console.log(errorThrown);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
It is also possible to import an html
document
to current document
using <link>
element with rel
attribute set to "import"
, see How to append a whole html file with jquery.
Upvotes: 1