I'm loading a page via $.ajax()
and inserting parts of the result into the corresponding parts of the page:
$.ajax({
url: '/whole_page.html',
success: function (data, status, xhr) {
$result = $(xhr.responseText);
$('#menu').html($('#menu', $result).html());
$('#content').html($('#content', $result).html());
}
});
Works like a charm, but I've run into a problem.
Now my pages contain some page-specific JS which must be executed when the result is fetched and inserted. As far as I can tell, jQuery won't return script
elements if you construct a jQuery object from HTML text and query against it (I've made a fiddle to demonstrate). So, I have no way of selectively inserting only the scripts I want via jQuery.
So it would seem that I've got to pull the script
elements from response text myself. Essentially, I'm looking for the right way to do this. Here's what I came up with so far:
function pullScripts(text) {
var frag = document.createDocumentFragment()
, div = document.createElement('div')
, scriptElements
;
// This is roughly how jQuery finds the scripts when cleaning text
frag.appendChild(div);
div.innerHTML = text;
scriptElements = div.getElementsByClassName('class-for-scripts-that-we-want');
$('head').append(scriptElements);
}
This works well enough, although I haven't tested it on any crappy browsers yet. Regardless, it feels uncomfortable to replicate such basic functionality of jQuery just to avoid one of its features (the special script
handling). As can be seen in the fiddle, the jQuery object actually does contain the script
s, but it won't return them with something like .html()
or .get()
. Am I missing some obvious way of doing this?
Note: this whole topic will be moot once jQuery's internal parseHTML
function is exposed
Note 2: I've also read Trying to select script tags from a jQuery ajax get response however the accepted answer is "you can't" followed by "use a regex". Both of which are unsatisfactory
In jQuery 1.8.0b1, you can now use the $.parseHTML()
method to make this easier.
$.parseHTML(xhr.responseText,true)
will give you a jQuery object that includes script elements. You can then extract the script tags and append or execute them after you append the html.
$.ajax({
url: '/whole_page.html',
success: function (data, status, xhr) {
var $result = $.parseHTML(xhr.responseText,true),
$scripts = $result.find("script").add($result.filter("script")).detach();
$('#menu').html($('#menu', $result).html());
$('#content').html($('#content', $result).html());
$('head').append($scripts);
}
});
You may have to filter the scripts though to avoid double including jQuery on a case by case basis. It will depend on the content you are loading.
If upgrading jQuery isn't an option, you could just take the implementation of $.parseHTML
and include it as a plugin to your current jQuery
(function($) {
if (!$.parseHTML) {
var rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/;
// data: string of html
// context (optional): If specified, the fragment will be created in this context, defaults to document
// scripts (optional): If true, will include scripts passed in the html string
$.parseHTML = function( data, context, scripts ) {
var parsed;
if ( !data || typeof data !== "string" ) {
return null;
}
if ( typeof context === "boolean" ) {
scripts = context;
context = 0;
}
context = context || document;
// Single tag
if ( (parsed = rsingleTag.exec( data )) ) {
return [ context.createElement( parsed[1] ) ];
}
parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] );
return jQuery.merge( [],
(parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes );
}
}
})(jQuery);
While I was playing with jQuery (edge) last night on jsFiddle, I wasn't able to use .find()
and friends on the result of $.parseHTML()
. The problem was that $.parseHTML
returns an array of elements rather than a jQuery object, and if you make one with $()
you're back at the original problem. So, you still can't really use selectors. Not much of a hassle though:
$.ajax({
url: '/some_page.html',
success: function (data, text, xhr) {
var result = $.parseHTML(data, true)
, scripts = []
, i;
// filter the scripts somehow
for (i = 0; i < result.length; i++) {
if (result[i].getAttribute('class') === 'good') {
scripts.push(result[i]);
}
}
$('head').append(scripts);
}
});
I've made a working fiddle for this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With