jQuery evaluating JavaScript in HTML string with complications
This is driving me crazy...
What I am trying to do is update a portion of a webpage, and for reasons not worth explaining, the request is asking for a whole new HTML page (including its head) and then pulling out only the HTML that was contained within a specified element (identified by an ID).
Originally, I had the following JavaScript code that would run whenever an AJAX request for new HTML completed:
var $newContent = $(newHtmlContent);
loadingElement.innerHTML = $("#" + loadingElementId, $newContent).html();
This was great until I had a bit of HTML that was loaded that, contained within the specified element, included some scripts that needed to be run, so I changed it to this:
var $newContent = $(newH开发者_Python百科tmlContent);
$(loadingElement).html($("#" + loadingElementId, $newContent).html());
I have read that jQuery will evaluate any scripts with the HTML string argument of the html() function - however, it seems the issue is that the scripts are stripped before this call. Having had a look through firebug the following seems to be happening:
$(newHtmlContent) // includes all 'script' elements
$("#" + loadingElementId, $newContent) // has no scripts
$("script", $newContent) // empty jQuery object
Does anyone have any suggestions? Thanks in advance.
Did a quick test (fiddle), given the following markup as string:
<div id="root">
<div>some dynamic content</div>
<script type="text/javascript">alert("hello");</script>
<div class="desiredElement">after script</div>
</div>
jQuery will produce an object like
> [0]: #root
> [1]: script
[0]
will contain all of the html in #root
except for the script, the scripts are separated into their own objects. This seems to be true for all scripts within the markup.
So you could do something like this to run the script:
var $new = $(dynamicContent); // dynamicContent is string
var $desired = $new.find('.desiredElement');
$new.eq(1).appendTo('body'); // run the script
edit Never mind; I think you're sunk here. As soon as you hand over the content to jQuery, I'm pretty sure that your scripts are stripped out. The stuff trick below would work if "newContent" were actually part of the "native" page, but because it's in that fragment instantiated by jQuery, it's too late.
I think this will work, but I admit I haven't tried it with a loaded document like what you've got:
$('#loadingElement').html($('#' + loadingElementId, $newContent)[0].innerHTML);
The idea is to bypass jQuery when pulling out the contents of the loaded portion.
There's a long explanation of this issue here: http://forum.jquery.com/topic/jquery-removing-script-tags-from-html-string-when-using-html
From that discussion:
If you want to select/traverse part of an HTML string, and you want the
<script>
within the HTML string to be executed, you need to insert the HTML string into the DOM before selecting/traversing.
So it looks like the problem is that you're trying to pull elements out of the returned HTML without inserting it into the DOM first. Two possible solutions:
Insert the entire returned HTML into the DOM. The script tags will execute. Then remove the parts you don't need. It's not ideal, as it might display content you don't want, unless you hide the
loadingElement
first and show when you're done.Pull out the script URLs from
$(newHtmlContent)
, use$.getScript()
to retrieve and execute each URL, then add the retrieved elements into the DOM. It's more of a pain, but it should work fine, and you don't have to insert unnecessary content into the DOM.
One thing you could try would be to pull out the contained <script>
elements and either eval()
them or append them into the head
of the page.
I'm guessing here as well but how about:
//scripts will be executed and HTML put into loadingElement
$('#loadingElement').html(newHtmlContent);
//find the specified element under #loadingElement, get it's HTML
//and set it as the HTML for #loadingElement
$('#loadingElement').html($('#loadingElement').find('#idToFind').html());
精彩评论