1

I am selecting a group of table rows by using the following line of JS:

document.getElementById('tab1_content').contentDocument.documentElement.getElementsByClassName("data1_smaller")

These represent entries in a table of contents. I want to return only those above which also contain the word 'CHAPTER', so I was attempting to use the jQuery :contains() selector to accomplish this and attempted to convert the entire thing into a single jQuery selector; so, to begin with, I tried converting the following invalid line:

document.getElementById('tab1_content').contentDocument.documentElement.getElementsByClassName("data1_smaller").$(":contains('CHAPTER')")

to this:

$("#tab1_content > contentDocument > documentElement > .data1_smaller:contains('CHAPTER')")

The selector above doesn't give an error but it fails to find anything. Does anybody know the correct way to do this?

gnorman
  • 163
  • 10
  • How is it supposed to work? `contentDocument`, `documentElement` are not valid html tags – Anurag Srivastava Nov 24 '20 at 15:27
  • I am working with a site which uses iframes. The ID "tab1_content" references an iframe and .contentDocument.DocumentElement references the body of the page loaded in the frame. The entire line.. document.getElementById('tab1_content').contentDocument.documentElement.getElementsByClassName("data1_smaller") .. selects all of the table of contents rows loaded in the frame. – gnorman Nov 24 '20 at 15:29
  • 1
    Does this answer your question? [How to expose IFrame's DOM using jQuery?](https://stackoverflow.com/questions/1654017/how-to-expose-iframes-dom-using-jquery) – Anurag Srivastava Nov 24 '20 at 15:30
  • 1
    Thanks! That set me on the right path. This worked: $("#tab1_content").contents().find(".data1_smaller:contains('CHAPTER')") – gnorman Nov 24 '20 at 15:37

3 Answers3

2

You can achieve what you want with pure vanilla js just like you tried in the beginning. You just need to do some small adjustments to your code. You can use querySelectorAll() to query all elements matching a selector inside your ID. Something like this should work just by looking at your example, but might need some small adjustments.

[...document.getElementById('tab1_content').querySelectorAll(".data1_smaller")].filter((node) => node.textContent.includes('CHAPTER'))

// Edit, saw in the comments that you're accessing content in an iframe
[...document.getElementById('tab1_content').contentWindow.document.querySelectorAll(".data1_smaller")].filter((node) => node.textContent.includes('CHAPTER'))
Thejool
  • 514
  • 4
  • 9
  • I wasn't familiar with filters but it seems really handy. I had trouble getting it to work with the iframes, though. VM425:1 Uncaught TypeError: document.getElementById(...).contentWindow.document.querySelectorAll(...).filter is not a function at :1:99 – gnorman Nov 24 '20 at 15:41
  • They are very handy indeed! You're right, I must have answered a bit too quickly, was actually an error in my code. I've updated the answer so the code is correct now. You can't use `filter` or `map` on `NodeList` which we get from `querySelectorAll` so we first have to convert it to an array before being able to filter. – Thejool Nov 24 '20 at 15:49
  • Thanks, that does work now! Your solution uses some syntax that I'm not familiar with, the [... at the beginning. I'm assuming it converts the result to an array. – gnorman Nov 24 '20 at 15:54
  • 1
    Awesome! Yes, you are correct, it's "converting" the result to an array. It's called "spread syntax" (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax). You could also achieve the same using `Array.from()`. – Thejool Nov 24 '20 at 16:00
1

I found this solution based on Anurag Srivastava's comments:

$("#tab1_content").contents().find(".data1_smaller:contains('CHAPTER')")

The issue was that I was trying to select things that are inside of an iframe and the the .contentDocument.documentElement that I used to access the iframe in JS has to be changed to .contents() in jQuery in order for it to work.

gnorman
  • 163
  • 10
0

Neither contentDocument or documentElement are valid HTML tags. Try to select by id or class name.

Or Assayag
  • 5,662
  • 13
  • 57
  • 93