Dmitry Minkovsky
Dmitry Minkovsky

Reputation: 38143

jQuery() not finding elements in jQuery.parseHTML() result

I'm writing tests with QUnit and using $.ajax() to pull in HTML for some of the tests from the the dev site running on my local:

add_elements = function(location, selector) { 
  $.ajax(location, {async: false}).done(function(data) {
    stor.$els = $(selector, $.parseHTML(data));
    stor.$els.appendTo($('body'));
  })
}

Using this function at a certain location, I get the following data passed to my .done() callback:

<!DOCTYPE html>
<html lang="en">

<head>
    <title>Home</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="/static/css/bootstrap.min.css" rel="stylesheet" media="screen">

</head>

<body>
<div id="app-container" class="container-fluid">
    <div class="page-header">
        <h1>
            <a href="/">Home</a>
            <small>Text</small>
        </h1>
    </div>

    <div id="hero-units" class="carousel-inner slide">

        <div class="hero-unit home item active">
            <h1>
                Text text text
            </h1>
            <p>
                More text!
            </p>
            <div id="app-nav">
                <a id="lets-go" class="btn btn-primary btn-large nav-forward" href="/what-up/">
                    Let's go
                </a>
            </div>
        </div>

    </div>
</div>

<script src="/static/js/jquery.js"></script>
<script src="/static/js/underscore.js"></script>
<script src="/static/js/backbone.js"></script>
<script src="/static/js/bootstrap.js"></script>
<script src="/static/js/site-fiddle.js"></script>
<script src="/static/js/site.js"></script>

</body>
</html>

Everything works if selector is #hero-units or .hero-unit, but $(selector, $.parseHTML(data)) returns nothing if selector is #app-container! And I want a jQuery object for the div#app-container element.

And here is what kills me:

What's going on here? It appears that what's happening is that $ is not looking at any of the top-level elements returned by $.parseHTML(data) or $($.parseHTML(data))), and just their children.

How can I get a jQuery object for div#app-container from this $.parseHTML(data)?

ANSWER

The $(selector, $.parseHTML(data))-style lookup uses $.find. Since I'm looking for an element that's top-level in this jQuery object, I should use $.filter instead. Voila.

Upvotes: 38

Views: 49444

Answers (7)

Jeroen Verheyden
Jeroen Verheyden

Reputation: 51

Above answers didn't work for me, this did:

use jQuery.parseHTML to parse the HTML into an array of elements; then you’ll be able to convert it to a jQuery collection and use filter to restrict the collection to elements matching a selector.

var html =
'<td class="test">asd</td>' +
'<td class="last">jkl</td>';
var obj = $($.parseHTML(html)).filter('.test');

Upvotes: 2

Robert Moskal
Robert Moskal

Reputation: 22553

It doesn't have anything to do with the html not being part of the DOM. It's just that for whatever reason the top level tag(s) in the parsed HTML cannot be found. If the element you are looking for is wrapped in another tag, then the find works as you expect. BTW, wrapping the element in the body tag won't work, but all the others I have tried work fine.

var bad = $.parseHTML('<ul><<li><one/li>/<li>two</li></ul>');
console.log($(bad).find('li').length);  //will be 2
console.log($(bad).find('ul').length);  //will be 0 

var good = $.parseHTML('<div><ul><<li><one/li>/<li>two</li></ul></div>');
console.log($(good).find('li').length); //will be 2
console.log($(good).find('ul').length); //will be 1

This is definitely the case in jQuery 1.11, not sure what happens in later versions. Here is a fiddle that demonstrates: http://jsfiddle.net/ndnnhf94/

Upvotes: 4

jcubic
jcubic

Reputation: 66490

You can try this:

$($.parseHTML('<div><span id="foo">hello</span></div>')).find('#foo');

for strings that start with < you can shorter that code to just:

$('<div><span id="foo">hello</span></div>').find('#foo');

Upvotes: 14

Stephon Lawrence
Stephon Lawrence

Reputation: 71

I believe this will work, especially if you specifically need to find the element by id;

function findInParsed(html, selector){
    return $(selector, html).get(0) || $(html).filter(selector).get(0);
}

If you need the jquery version of the object then you can get it with this

function findInParsed(html, selector){
    var check = $(selector, html).get(0);
    if(check)
        return $(check);
    check = $(html).filter(selector).get(0)
    return (check)? $(check) : false;
}

Upvotes: 0

adu
adu

Reputation: 987

Just ran into this.

Turns out $.parseHTML returns a vanilla Array of DOM elements, and that doesn't support the jQuery find that you want.

I think this is the cleanest solution for converting an HTML string to a jQuery object:

var html = '<div><span id="foo">hello</span></div>';
var $foo = $(html).find('#foo');

Note: You may want to use $.trim around your html strings so jQuery doesn't get confused by whitespaces.

Upvotes: 4

Amy
Amy

Reputation: 7466

You need to create a DOM element to append the results of .parseHTML() first so that it creates a DOM tree before jQuery can traverse it and find div#app-container.

var tempDom = $('<output>').append($.parseHTML(str));
var appContainer = $('#app-container', tempDom);

I used your example and got it working: http://jsfiddle.net/gEYgZ/

The .parseHTML() function seems to choke on the <script> tags, so I had to remove them.

PS. Obviously <output> is not a real HTML tag, just using it for the example

Upvotes: 42

Jai
Jai

Reputation: 74738

i think you should try with this:

$('body', $.parseHTML(data))

Upvotes: 0

Related Questions