11

I'm trying to learn jQuery's ajax functions. I've got it working, but jQuery doesn't find elements in the returned HTML DOM. In the same folder as jquery, run this page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
    <title>runthis</title>

    <script type="text/javascript" language="javascript" src="jquery-1.3.2.min.js"></script>

    <script tyle="text/javascript">
    $(document).ready(function(){
        $('input').click(function(){
            $.ajax({
                type : "GET",
                url : 'ajaxtest-load.html',
                dataType : "html",
                success: function(data) {

                alert( data ); // shows whole dom

                alert( $(data).find('#wrapper').html() ); // returns null

                },
                error : function() {
                    alert("Sorry, The requested property could not be found.");
                }
            });
        });
    });
    </script

</head>
<body>
    <input type="button" value="load" />
</body>
</html>

Which loads this page "ajaxtest-load.html":

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
    <title>load this</title>

</head>
<body>
    <div id="wrapper">
    test
    </div>
</body>
</html>

It gives two alerts. One showing the DOM was loaded, but the second shows NULL instead of the #wrapper. What am I doing wrong?

EDIT: I'm loading "ajaxtest-load.html" which includes the whole header, including jquery again. Is that the issue?

arogachev
  • 33,150
  • 7
  • 114
  • 117
user110218
  • 165
  • 2
  • 2
  • 9

4 Answers4

9

This is not a direct answer, but may help to clarify things.

The data parameter of the callback function can be made into a jQuery (1.6.2) object $(data), which contains the different parts of the HTML response:

  • Stuff that precedes the actual document, such as a doctype declaration, or ignorable white space textnodes.
  • The contents of the head element.
  • The contents of the body element.

The html, head and body elements are not in the data object. Since the number of elements contained in head and body may vary, you should not get them by indexing like $(data)[2]. Instead, apply a filter to this object, like this:

        $.get(
          uri,
          function(data, textStatus, jqXHR){
            var $doc = $(data);
            var title = $doc.filter('title').text();
            // title is the title from the head element.
            // Do whatever you need to do here.
          }
        );

After filtering the right elements, you can apply further selectors using find().

Unfortunately, in IE the head elements are not part of $(data). I have no idea why this is.

rakensi
  • 1,437
  • 1
  • 15
  • 20
  • 2
    +1 because this works with the latest `.ajax()` implementation as well. I just changed `.find()` to `.filter()` and it all worked! – chrisfrancis27 Oct 23 '12 at 09:21
  • 1
    I spent hours trying to figure out why it wouldn't find a specific element, but it found all the elements inside. Switching out `.find()` to `.filter()` made it work. Thank you so much! Also, i want to punch a baby in the face. Not even kidding, that's how mad i am. – qwerty Mar 08 '13 at 15:58
8

I've managed to load snippets off of full html-documents just fine by using .load().

To create a new block with extracted html into the DOM I do this:

$('<div></div>').appendTo('body').load('some-other-document.html div#contents');

If it's not working for you, make sure you're using the most recent version (or post 1.2) of jQuery. See the documentation for .load for more examples.

Edit:

Note, though, that with the above example the result will be:

<div><div id="contents">...</div></div>

To get just the contents of the #contents div in the other document, use a callback-function in the load-function call.

$('<div></div>').load('some-other-document.html div#contents', null, 
    function (responseText, textStatus, XMLHttpRequest) {
        if (textStatus == success) {
            $('<div></div>').appendTo('body').html($(this).html());
        }
    }
);
nikc.org
  • 16,462
  • 6
  • 50
  • 83
  • 1
    I like this because it avoids sticking the returned data into the document immediately. FYI, if you don't mind creating a dummy div and inserting the returned data into it, you can do that inside of `$.get()`. That's essentially what `.load()` does under the hood. – Nathan Long Dec 03 '10 at 16:51
  • thanks, it is the perfect solution I needed for my project. In my ajax calls I receive the data requested by the user (either a tooltip, the page content or something else) and it needed to always be accompanied by a json object to update the user's widgets... Dividing the requested info and the json object has been executed by sending 2 divs and your technique allows me to do .find() to return the needed data. Thanks again – Salketer Mar 06 '13 at 13:52
3

I found that if ajaxtest-load.html does not have <html> or <body> tags but just a few html elements, it does work.

Edit:

If the input has to be a full HTML page, maybe you can first strip of the tags you don't want with string operations.. anyone?

Edit 2:

Vaguely remembered Javascript/DOM allowed for "temporary documents" which you could operate on and use the results from, then a bit of googling yielded a parseHTML function (http://www.daniweb.com/forums/post874892-2.html) which I've adapted to return the right bit:

$(document).ready(function(){
  $('input').click(function(){
    $.ajax({
      type : "POST",
      url : 'ajaxtest-load.html',
      dataType : "html",
      success: function(data) {
        alert( data ); // shows whole dom
        var gotcha = parseHTML(data, 'wrapper');
        if (gotcha) {
          alert($(gotcha).html());
        }else{
          alert('ID not found.');
        }
      },
      error : function() {
        alert("Sorry, The requested property could not be found.");
      }
    });
  });
});

function parseHTML(html, idStr) {
  var root = document.createElement("div");
  root.innerHTML = html;
  // Get all child nodes of root div
  var allChilds = root.childNodes;
  for (var i = 0; i < allChilds.length; i++) {
    if (allChilds[i].id && allChilds[i].id == idStr) {
      return allChilds[i];
    }
  }
  return false;
}

Does that work?

MSpreij
  • 1,142
  • 13
  • 20
  • Oh, maybe a regex to strip out the body or something? And then use jQuery to convert that to an object that I can .find() on? – user110218 Jun 23 '09 at 16:49
  • Something like that, yes. I'd have supplied an example but my JS regex isn't that fantastic, and I'm double wary of giving regex examples when I've very little idea what might be in the content :-) (Like, the body could have attributes containing a '>') But willing to try.. – MSpreij Jun 23 '09 at 17:06
2

Why not try this and see what happens:

$('#testDiv').load('ajaxtest-load.html #wrapper', function(resp) {
    alert(resp);
});

From the $.load documentation:

In jQuery 1.2 you can now specify a jQuery selector in the URL. Doing so will filter the incoming HTML document, only injecting the elements that match the selector.

karim79
  • 339,989
  • 67
  • 413
  • 406
  • Thanks, but running that, firebug showed the error '$.load' is not a function. – user110218 Jun 23 '09 at 16:31
  • You can't just use $.load. You have to use it on a selector like $(selector).load() – Tim Banks Jun 23 '09 at 16:33
  • @T B - yeah, don't know what I was thinking. @threebttn Sorry about that, try using it to fill up a div. See my edit. – karim79 Jun 23 '09 at 16:36
  • I modified it to populate a div, but still no luck. I think it's because it's a full HTML DOM instead of an HTML snippet (per the answer below, too). Could that be the problem? How do I parse a full HTML DOM? – user110218 Jun 23 '09 at 16:45
  • Uhm, not sure from which activities one gets alerts here (new to SO) so I'll just comment the main question.. I updated my post below a bit with a parseHTML function, hope that helps – MSpreij Jun 23 '09 at 17:40