aprea
aprea

Reputation: 109

Get contents of <body> </body> within a string

I want to do the following.

$("a").click(function (event) {

    event.preventDefault();

    $.get($(this).attr("href"), function(data) {

        $("html").html(data);

    });

});

I want the behavior of all hyperlinks to make a ajax calls and retrieve the html.

Unfortunately you cannot simply replace the current html with the html you receive in the ajax response.

How can grab only what is within the <body> </body> tags of the ajax response so that i can replace only the contents of the body in the existing html.

Edit: the <body> opening tag will not always be just <body> it may sometimes have a class e.g.

<body class="class1 class2">

Upvotes: 5

Views: 23137

Answers (3)

Chris Baker
Chris Baker

Reputation: 50592

Be sure to bind events to the document, filtered by class ($(document).on('click', '.my-class-name', doThings);) If you replace the html of the body, any event bindings done directly ($('.my-class-name').on('click', doThings);) will be destroyed when DOM is redrawn using the new html. Rebinding will work, but it will also leave a bunch of pointers from the old events and nodes that the garbage collector will have to clean up -- in simpler terms it may make the page get heavier and heavier the longer it is open.

I have not tested this on multiple platforms, use with caution.

// create a new html document
function createDocument(html) {
  var doc = document.implementation.createHTMLDocument('')
  doc.documentElement.innerHTML = html
  return doc;
}
$("a").click(function (event) {
    event.preventDefault();
    $.get($(this).attr("href"), function(data) {
        $("body").html($(createDocument(data)).find('body').html);
    });
});

Upvotes: -1

Peter V. M&#248;rch
Peter V. M&#248;rch

Reputation: 15907

I didn't want to mess with regular expressions. Instead, I created a hidden <iframe>, loaded the contents in it, and extracted the <body> from the page in the <iframe> in the page's onload().

I needed to be careful with Same-origin policy for the the iframe (this article showed the way):

var iframe = document.createElement('iframe');
iframe.style.display = "none";
jQuery('body').append(iframe);
iframe.contentWindow.contents = data;
iframe.onload = function () {
    var bodyHTML = jQuery(iframe).contents()
                        .find('body').html();
    // Use the bodyHTML as you see fit
    jQuery('#error').html(bodyHTML);
}
iframe.src = 'javascript:window["contents"]';

Just remove the <iframe> when you're done...

Upvotes: 1

Rob Raisch
Rob Raisch

Reputation: 17357

If I understand you correctly, grab the content between the body tags with a regex.

$.get($(this).attr("href"), function(data) {
    var body=data.replace(/^.*?<body>(.*?)<\/body>.*?$/s,"$1");
    $("body").html(body);

});

EDIT

Based on your comments below, here's an update to match any body tag, irrespective of its attributes:

$.get($(this).attr("href"), function(data) {
    var body=data.replace(/^.*?<body[^>]*>(.*?)<\/body>.*?$/i,"$1");
    $("body").html(body);

});

The regex is:

^               match starting at beginning of string

.*?             ignore zero or more characters (non-greedy)

<body[^>]*>     match literal '<body' 
                    followed by zero or more chars other than '>'
                    followed by literal '>'

(               start capture

  .*?           zero or more characters (non-greedy)

)               end capture

<\/body>        match literal '</body>'

.*?             ignore zero or more characters (non-greedy)

$               to end of string

Add the 'i' switch to match upper and lowercase.

And please ignore my comment regarding the 's' switch, in JavaScript all RegExp are already single-line by default, to match a multiline pattern, you add 'm'. (Damn you Perl, interfering with me when I'm writing about JavaScript! :-)

Upvotes: 12

Related Questions