Isaac B
Isaac B

Reputation: 755

How do I climb up and down the DOM Tree using element Tag names?

I know how to climb up and down the DOM using parentNode, children and id's, but I don't know how to access a sibling or child element by tag name alone.

This code example is a bit contrived, but I'm hoping you can use it to help me with a general answer to navigating using these element tag names.

//fluff to create an example
const outArr = Array(10).fill(0).map( (el, i) => { return (
  '<p>Title ' + i + '</p>' +
  '<p>Decription ' + i + '</p>' +
  '<span>Other ' + i + '</span>' +
  '<button>Click to Like' + i + '!</button>'
  )});
const output = outArr.join(',');
document.getElementById('ex-container').innerHTML = output;

//targeting inside anon event function for simplicity
document.getElementById('ex-container').addEventListener('click', function(e) {
    if (e.target.localName == 'button') {
      const curEl = e.target
      const parent = curEl.parentNode;
      
      //I can access the parent node. If I had id's, I know I could targert
      //children with those. How would I target the siblings, and from the
      //parentNode target a specific child by element tagName, such as p?
      console.log('curEl: ', curEl);
      console.log('parent: ', parent);
    }
    e.stopPropagation();
});
<div id='ex-container'>
<!--  everything goes here -->
</div>

Bonus: how can I target the nearer p sibling by tag name?

Upvotes: 1

Views: 1684

Answers (2)

zer00ne
zer00ne

Reputation: 43853

Added some properties to address the questions commented in source (couldn't understand question). Details are comment by /* */ in the Snippet.

SNIPPET

//fluff to create an example
const outArr = Array(10).fill(0).map((el, i) => {
  return (
    '<p>Title ' + i + '</p>' +
    '<p>Decription ' + i + '</p>' +
    '<span>Other ' + i + '</span>' +
    '<button>Click to Like' + i + '!</button>'
  )
});
const output = outArr.join(',');
document.getElementById('ex-container').innerHTML = output;

//targeting inside anon event function for simplicity
document.getElementById('ex-container').addEventListener('click', function(e) {
  /* Compare the currentTarget to the target, this way it
  || will give you target to whatever you clicked not just a
  || button 
  */
  if (e.target !== e.currentTarget) {
    const curEl = e.target
    const parent = curEl.parentNode;
    // How would I target the siblings,
    var bigBro = curEl.previousElementSibling;
    var lilBro = curEl.nextElementSibling;
    /* Collect all children of parent */
    var kids = parent.children;
    // from the parentNode target a specific child by element tagName, such as p?
    /* Same results for both with one difference being the
    || first one is "live" NodeList  the other "static"
    || NodeList. 90% of the time, it's safer to go "static"
    || using querySelectorAll() 
    */
    var paragraphsByTag = parent.getElementsByTagName('p');
    var paragraphsBySel = parent.querySelectorAll('p');

    console.log('curEl: ', curEl);
    console.log('parent: ', parent);
    console.log('bigBro: ', bigBro);
    console.log('lilBro: ', lilBro);
    /* Add .length property to get total number */
    console.log('Total Kids: ', kids.length);
    /* NodeLists are array-like but not true arrays, so use
    || Array.from() to convert them into true arrays. 
    */
    console.log('Paragraphs are: ', Array.from(paragraphsBySel));
  }
  /* Specific by tagName is almost an oxymoron. If you
  || want to target a specific element but only have
  || tagNames, then as you commented, by index is the way
  || to go.
  */
  console.log('The 6th paragraph is: ', Array.from(paragraphsBySel)[5]);

  e.stopPropagation();
});
<div id='ex-container'>
  <!--  everything goes here -->
</div>

Upvotes: 1

Brett DeWoody
Brett DeWoody

Reputation: 62743

Check out document.querySelector(). You can use querySelector() on a node to select child nodes by selector. Ex.

const parent = document.getElementById('someID')
const firstP = parent.querySelector('p:first-child')

parent would ref the element with ID of someID, and from there we can use querySelector on parent to select the first p tag.

Here's a working example:

const parent = document.getElementById('someID')
const firstP = parent.querySelector('p:first-child')

firstP.style.color = 'red'
<div id="someOtherID">
  <p>First</p>
  <p>Second</p>
  <p>Third</p>
  <p>Fourth</p>
</div>
<div id="someID">
  <p>First</p>
  <p>Second</p>
  <p>Third</p>
  <p>Fourth</p>
</div>

You can use the related document.querySelectorAll() to create an array of matching elements and do something along the lines you want, like this:

const parent = document.getElementById('someID')
const pees = parent.querySelectorAll('p')

parent.pees = Array.from(pees)

parent.pees[0].style.color = 'red'
<div id="someOtherID">
  <p>First</p>
  <p>Second</p>
  <p>Third</p>
  <p>Fourth</p>
</div>
<div id="someID">
  <p>First</p>
  <p>Second</p>
  <p>Third</p>
  <p>Fourth</p>
</div>

Upvotes: 1

Related Questions