52

I have

$.ajax({
  url: identity,
  success: function(data) { ProcessIdentityServer(data) }
});

When 'data' is returned, is there a way to run selectors against it without adding it into the DOM. So for example, how can I get all the href values of any LINK tags contained in the HTML held in 'data' without adding it to the DOM first? Seems a shame to have to add it into the DOM if all I want to do is extract some stuff into an array. Anyone got any ideas?

9 Answers 9

113

One note I will add which is from a similar problem on here is that if your AJAX returns the following:

<div class="test">Hello</div>
<div class="one">World</div>

The following jQuery Won't work:

$(data).find('div.test');

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('div.test');
Sign up to request clarification or add additional context in comments.

4 Comments

seriously this answer was way too helpful.. spent half a day on this.!
This is THE answer. Too bad it wasn't voted as the right one originally!
SIMPLY:: THE ANSWER
I used to be able to do $('div.test', data); - am I imaging things or did that stop working at some point?
40
// Finds all div elements within an XML document from an AJAX response.
$("div", xml.responseXML);

4 Comments

I voted this one up, though on second thought, I think that calling find explicitly is more readable, especially to someone who's less familiar with the framework.
For anyone else coming across this thread, simply use jQuery's load() method to grab a portion of the returned AJAX response E.g. jQuery('#container').load('ajax/test.html #selector',function(){ ... }) . Or for grabbing multiple portions see here link
Please do read @stuartloxton's reply coming next, as that contains the answer.
Please give a detailed explanation.
37

Before beginning, let's take a quick look at what jQuery does to a basic HTML page returned from an $.ajax() call, and converting the returned data into a jQuery object.

$.ajax({
    dataType : 'html',
    url      : 'path/to/example-page.html',
    success  : function(data) {

        // log the result of the data converted into a jquery object.
        console.log( $(data) );

    }
});

Here's what you would expect to see:

[

    0         <TextNode textContent="\n\n\n\n\n ">
    1         title
    2         <TextNode textContent="\n ">
    3         meta
    4         <TextNode textContent="\n\n\n\n\n">
    5         div#container
    6         Comment { data=" #container ", length=12, nodeName="#comment", more...}
    7         <TextNode textContent="\n\n">
    jquery    "1.6.4"
    length    8
    selector  ""

    // additional data and functions removed for brevity

]

YIKES! That's quite ugly! Attempting to do anything with that can yield results, but you need to know what the data structure looks like every single time, and where the data lie within that object. Is that data at the root, or is it buried within?

Like previous posters have mentioned, you can use .filter(), but the root is as far as that search will go, because you're simply filtering the returned results. However, if you were to use .find() at this point and the element you wanted is at the root, you'll receive an empty set, but anything buried beyond the root will be found.

So, why be pinned down to needing to know what that data structure looks like with 100% certainty, and why bother going through all the trouble of having to use multiple .filter() and .find() calls, and dare I say an .each() loop? Yuck! That's just simply too much work and takes way too much time.

If you want to .find() a particular HTML element returned from an .ajax() call, start with the following line:

var response = $('<html />').html(data);

Can it really be that easy? In fact, yes it is! What's happening here is that a new <html> element is being created and converted into a jQuery object. This is used a starting location to insert the returned HTML from an .ajax() call. It's kind of like doing $('html') on a webpage. With this, you can begin finding elements.

response.find( ... ); // any jquery selector in place of the ellipsis.

Here's an example that uses the original poster's question:

$.ajax({
    dataType : 'html',
    url      : 'path/to/example-page.html',
    success  : function(data) {

        // set the returned contents in a new base <html> tag.
        var response = $('<html />').html(data),
            anchors, hrefValuesList = [ ],
            i, end;

        // now you can search the returned html data using .find().
        anchors = response.find('a');

        // grab all your href values from each anchor element.
        end = anchors.length;
        for (i = 0; i < end; i++) {
            hrefValuesList.push( anchors[ i ].href );
        }

        // continue processing the data as necessary...

    }
});

Obviously the above will need some refining if you want to filter out any unwanted content, or want to refine the values returned.

With that, you could see something like the following example array returned:

[ "http://stackoverflow.com/", "http://www.google.com/" ] // and so on...

Using this approach, you can easily use the power of .find() on any HTML data returned through the $.ajax() function like you already do on any elements you find in the DOM. The real bonus is that you aren't directly manipulating the DOM to find or do what you want, which is an expensive process.

Happy scrubbing! =)

3 Comments

"Without adding it into the DOM" - I would expect that $('<html />').html(data) would take about the same processing as $("#someExistingDiv").html(data) would, no? Still a very thorough answer...
@mplungjan -- One would probably think so. By doing a simple unit test in Firefox 7.0, you would see that $('#someExistingDiv').html(data) runs, on average, about 4x slower than $('<html />').html(data). This is because the former manipulates the DOM, which causes browser reflow. Now, if you want to say that $('#someExistingDiv') is faster than $('<html />'), you would be correct. If you do this multiple times, using the new element approach should be faster in the end, because any time the DOM is accessed, it adds time to the overall execution. Plus, the new element can be reused.
Amazing... Thank you for the crystal clear response, this is exactly what I needed. Without converting the string to a jQuery object, the find method solution was throwing errors for me in Internet Explorer; this solution is ideal.
20

Presuming that data is a string of HTML, you can do this:

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

That will return the links without adding the data to the DOM.

1 Comment

this doesnt seem to work, yet .filter instead of .find does. as @stuartloxton answers
3

You have to define a container first, to be able to get/modify the elements from the response:

 $.ajax({            
     url: url + "/ajax.htm",
     dataType: "html",
     success: function(html) {
         container = $('#ajax_content');
         container.html(html);
         container.find("a").css("background","red");
     }
 });

Comments

2

Sure you can use the $(data) function, one of the core jquery functions, to turn the returned html into DOM elements. Check out the docs online.

Comments

2

You can also use context now (don't know when this was introduced):

$.get('some/url', '',
    function (data) {
        $("#domelement", data);
    }
);

1 Comment

not sure why this hasn't got more upvotes. context has been around since jQuery v 1.0
1

This is the same as the accepted answer but with some extra explanation.

You may use the jQuery context parameter Link to docs

I can't really explain better than the documentation.

Selector Context

By default, selectors perform their searches within the DOM starting at the document root. However, an alternate context can be given for the search by using the optional second parameter to the $() function

The context parameter has been around since jQuery v1.0

Therefore a solution to the OP's example to "get all the href values of any LINK tags contained in the HTML held in 'data' without adding it to the DOM first" would be:

success: function(data){
    $("a", data).each(function(){
        console.log( $(this).attr("href") );
    });
}

Comments

0

my ultimate solution was

jQuery.ajax({
    url: "/some-url",
    cache: false,
    dataType: "html",
    success: function(data) {
        jQuery("#target").html( jQuery(data).find('#ajax-data'));
    }
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.