skip to Main Content

I got an html page through an AJAX request

$.ajax({
    async: true,
    method: 'GET',
    url: linkPage,
    // cache: true,
    success: function (data) {
        console.log(data);
    }
});

The data format I get like this:

<!DOCTYPE html>
<html>
<head>
...
</head>
<body id="sustainable" class='sustainable'>
<div id="wrap">
    <main class="temp>
        <section class="sec01">
            ...
        </section>
    </main>
</div>
</body>
</html>

Now I want to get the body id and class (which is “sustainable”) via this code:

$(data).find('body').attr('class');

But I have no idea why I can’t get that, it returns undefiend. But when I get html content or class of <main> by this code:

$(data).find('main').attr('class');
$(data).find('main').html();

It returns exactly what I want. Can anybody explain me why?

I’ve tried some solutions so far by create a virtual DOM like this, and I can select <body> and <main> from AJAX data as I want: Cannot get body element from ajax response

But I still wonder why I can’t select <body> class and html as first case?

3

Answers


  1. The following jQuery Won’t work:

    $(data).find('sustainable');
    

    as the divs are top level elements and data isn’t an element but a string, to make it work you need to use .filter

    $(data).filter('sustainable.wrap');
    
    Login or Signup to reply.
  2. It looks like, when given a string like that, jQuery will only save the contents of the body into its collection:

    const data = `<!DOCTYPE html>
    <html>
    <head>
    ...
    </head>
    <body id="sustainable" class='sustainable'>
    <div id="wrap">
        <main class="temp>
            <section class="sec01">
                ...
            </section>
        </main>
    </div>
    </body>
    </html>`;
    console.log($(data)[0]);
    console.log($(data)[1]);
    console.log($(data)[2]);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    (Check your browser console. It’s selecting the text nodes around #wrap, and #wrap itself, but not the <head> or <body>)

    You could use DOMParser instead, which will try to turn the whole string into a document, without trying to leave things out:

    const data = `<!DOCTYPE html>
    <html>
    <head>
    ...
    </head>
    <body id="sustainable" class='sustainable'>
    <div id="wrap">
        <main class="temp>
            <section class="sec01">
                ...
            </section>
        </main>
    </div>
    </body>
    </html>`;
    const doc = new DOMParser().parseFromString(data, 'text/html');
    console.log(doc.body.className);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    Another benefit of using DOMParser is that, unlike jQuery, it won’t execute possibly-unsafe code in the HTML string:

    const data = `<!DOCTYPE html>
    <html>
    <head>
    ...
    </head>
    <body id="sustainable" class='sustainable'>
    <img src onerror="alert('evil')">
    </body>
    </html>`;
    $(data);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    jQuery version, unsafe
    const data = `<!DOCTYPE html>
    <html>
    <head>
    ...
    </head>
    <body id="sustainable" class='sustainable'>
    <img src onerror="alert('evil')">
    </body>
    </html>`;
    const doc = new DOMParser().parseFromString(data, 'text/html');
    console.log(doc.body.className);
    DOMParser version, safe
    Login or Signup to reply.
  3. The reason it doesn’t work the way you tried is explained in the jQuery documentation:

    If the HTML is more complex than a single tag without attributes, as it is in the above example, the actual creation of the elements is handled by the browser’s .innerHTML mechanism. In most cases, jQuery creates a new <div> element and sets the innerHTML property of the element to the HTML snippet that was passed in.

    Since you can’t have a <body> inside a <div>, the browser ignores the <body> tag.

    The documentation goes on to say:

    When passing in complex HTML, some browsers may not generate a DOM that exactly replicates the HTML source provided. As mentioned, jQuery uses the browser’s .innerHTML property to parse the passed HTML and insert it into the current document. During this process, some browsers filter out certain elements such as <html>, <title>, or <head> elements. As a result, the elements inserted may not be representative of the original string passed.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search