JQuery .find() failing on an .ajax() result

173 views Asked by At

I'm working on a Chrome extension which, under certain conditions, performs a $.ajax() request and then uses information of specific elements in the returned HTML. For now, I'm simply trying to have it access the specific element and log it to the console to ensure it works correctly.

To start, I am fairly certain the HTML is successfully retrieved. When I log the result directly, the output is identical to the result when I view the page source in Chrome. I've also tried using $.parseHTML() which, when logged, gives me an array of top-level children. Using selectors returns an array of the immediate children matching the selector, but they do not work for elements which are children of these children (and so on).

I've looked at several posts already, and tried a variety of things such as using $(<selector>,<context>), $(<result>).filter(<selector>), and $(<result>).find(<selector>) to no avail. Every time I try to log these I end up with an object of length 0.

$.ajax({jsonp: false, dataType: "html",url: getUWFlowLink($(this).attr('href')), success: function(siteHTML){

    console.log($("p.description",siteHTML));
    console.log($("p.description",$.parseHTML(siteHTML)));
    console.log($(siteHTML).find("p.description"));
    console.log($($.parseHTML(siteHTML)).find("p.description"));
    console.log($(siteHTML).filter("p.description"));
    console.log($($.parseHTML(siteHTML)).filter("p.description"));

}});

All of these logs simply return objects with 0 length. Trying to log the .html() results in an output of undefined, and trying to log the .text() results in an empty string for output. A sample page, for reference is here. The element I am trying to access is the description blurb at the top ("Chemical principles with applications...") and its location in the HTML (a few levels deep) can be found by inspecting the element.

3

There are 3 answers

1
Dhiraj On BEST ANSWER

Try something like this

var $result = $('<div />').append(siteHTML);
$result.find('p.description');

jQuery requires a tree structure to traverse and perform its operations. Directly trying to use .find() without having a root element would not work. In the above case $('<div/>') would be the root element and by appending the result, jquery would be above to traverse it and find p.description.

0
tonesforchris On

If you are successfully getting the HTML and not running into Access-Control-Allow-Origin issues, I have tested the below to work in test cases:

var description = $(siteHTML).find("p.description").html();
console.log(description);

If you can console.log(siteHTML) and it is giving you output, then you should be able to query the response with jQuery, however there may be some limitations to which query selectors work when not adding the HTML to the DOM.

4
rsanchez On

If you do a "View page source" for the sample page you linked, you'll find that the element you are looking for looks like this:

<script type="text/html" id="course-inner-tpl">

<div class="row-fluid">
  <div class="span6 left-col">
    <p class="description"><%- course.get('description') %></p>
...

This means that the element is being rendered on the browser dynamically after loading. It won't be part of the DOM tree when jQuery parses it, as it is inside a <script> tag.

Note that you can also find the course description on the same page in a static <meta> tag that you should be able to access.

EDIT: If you need additional information, you can parse the relevant script to get it. The following code will iterate over all the scripts in the page, find the one that contains the info, extract the text defining the coursOjb object, and parse it as JSON:

$('<div />').append(siteHTML).find('script').each(function(s) {
   var t = $(this).text();
   var p = t.indexOf('window.pageData.courseObj = {');
   if( p > 0 ) {
       var e = t.indexOf(';', p);
       var d = JSON.parse(t.substring(p+28, e));
       console.log(d.code);
       console.log(d.name);
       console.log(d.description);
       console.log(d.prereqs);
   }
});