4

i am new to JSDOM parser.

I have the following:

<div id='mydiv'>
  <ul>
    <li><a title='a'>TextA</a></li>
    <li><a title='b'>TextB</a></li>
    <li><a title='c'>TextC</a></li>
    <li><a title='d'>TextD</a></li>
  </ul>
</div>

I am using the following code but not able to get the text 'TextA', 'TextB', 'TextC', 'TextD'

const categoryDiv = dom.window.document.querySelectorAll('#mydiv > ul > li')
  .forEach(item => {
    console.log('item', item.getElement('a')); //not sure how to continue from here
  });
})
Mukil Deepthi
  • 6,072
  • 13
  • 71
  • 156

3 Answers3

1

Simply modify your original code with getElementsByTagName and innerHTML:

const categoryDiv = dom.window.document.querySelectorAll('#mydiv > ul > li')
.forEach(item => {
   console.log('item -- ' + item.getElementsByTagName('a')[0].innerHTML); 
 });
})
silencedogood
  • 3,209
  • 1
  • 11
  • 36
  • It's right that this code logs the items, but if you eventually want to have the text values stored in categoryDiv .forEach has to be changed to .map and the NodeList has to be converted to an array to be 'mappable' – Corrl Oct 26 '21 at 20:39
1
const categoryDiv = dom.window.document.querySelectorAll('#mydiv > ul > li')

After this first step you have a NodeList with the 4 list elements. With

console.dir(categoryDiv[0])

you can log the first list object to the console and see and expect all its properties. There are various ways to access the enclosed anchor tags. For example

  1. .children => HTML Collection
  2. .childNodes => NodeList
  3. .getElementsByTagName('a') => HTML Collection
  4. .querySelector('a') => href element

Only the last option gives you the link element directly, with the first three you have to select the first element in the selection to get to the link

For then accessing the text of the link there are again two options

  1. .innerHTML
  2. .textContent

In this case it doesn't matter which to choose because both give you the Text inside the link tags, if called on the link. If called on the list element it would look like this

listElem.outerHTML // <li><a title="a">TextA</a></li>
listElem.innerHTML  // <a title="a">TextA</a>
listElem.textContent // TextA

Sooo you actually don't have to access the link element. Simply call directly .textContent on the list items

Lastly you want to use .map instead of .forEach since .forEach only iterates, but doesn't return anything. The NodeList directly is not iterable with .map but can be easily converted with the spread operator

So all together for example like this

const categoryDiv = [...document.querySelectorAll('#mydiv > ul > li')]
  .map(listItem => listItem.textContent)

console.log(categoryDiv)  // ['TextA', 'TextB', 'TextC', 'TextD']

or this

const categoryDiv = Array.from(document.querySelectorAll('#mydiv > ul > li'), listItem => listItem.textContent)

Or a very fast way without even iterating would be

document.querySelector('#mydiv ul')
  .textContent  // 'TextA TextB TextC TextD'
  .split(' ')  // ['TextA', 'TextB', 'TextC', 'TextD']
Corrl
  • 6,206
  • 1
  • 10
  • 36
1

This could be as simple as:

  let targets = document.querySelectorAll('#mydiv > ul > li a');

  for (let target of targets) {
    console.log(target.text); 
  }
Jack Fleeting
  • 24,385
  • 6
  • 23
  • 45
  • Since you left out the > between li and a I'm wondering... all the others aren't necessary and could be omitted as well..? – Corrl Oct 26 '21 at 20:53
  • In fact you can drop all `>`s in this case; `>` restricts the selection to immediate children of the parent node (as opposed to descendants (grandchildren, etc.)). In this case, we are walking from one node down to its immediate child(ren) node(s) anyway, so the `>` isn't necessary; in other cases - it may definitely be. – Jack Fleeting Oct 26 '21 at 21:22
  • I see, so actually 'ul' and 'li' could be dropped as well and document.querySelectorAll('#mydiv a') would already be enough in this case – Corrl Oct 26 '21 at 21:32
  • @Corrl That's true - in this particular case. You should be careful, however, with what elements you select (or skip) when you're faced with more complex html or xml (deeply nested elements, etc.). For more heavy duty problems, you may have to switch from css selectors to the more-powerful xpath. It takes practice but over time you'll develop a better sense of what works when. – Jack Fleeting Oct 26 '21 at 22:37