Home > OS >  HTML Javascript: can't get all instances from two elements at once?
HTML Javascript: can't get all instances from two elements at once?

Time:09-27

I want to add a CSS styling class to all instances of a selective set of elements: for example, all p elements as well as all h4 elements.

I define two JS variables which get all elements of the aforementioned tags, and insert them into an array, so that I can make a function which, in theory, should apply the selected class to all instances of the selected elements/tags.

However, when I run the code, it seems that the function assigns the class only to the first item of the array.

Code and test

<html>
  <head>
    <meta charset="utf-8">
    <title>JS Bin</title>
    <style>
      .italic { font-style: italic; }
    </style>
  </head>
    <body>
      <h4>Text goes in here</h4>
      <p>Text goes in here</p>

      <script>
        function styleTxt() {
          let h4Elems = document.getElementsByTagName("H4");
          let pElems = document.getElementsByTagName("P");
          const elemArray = [pElems, h4Elems];

          for (eachElem in elemArray) {
            let elemInsts = elemArray[eachElem];
            for (eachInst in elemInsts) {
              let givenInst = elemInsts[eachInst];
              givenInst.classList.add("italic");
            }
          }
        }
        styleTxt();
      </script>

    </body>
</html>

If I invert the order of the element tags inside the array, then the h4 element will get the .italic class but the p element will not.

Perhaps it is not possible to use the "document" directive twice? Is there an alternative method to automatically add the same class to a set of multiple (but not all) html tags?

CodePudding user response:

You are looping through each property of the HTMLCollection, including properties like length, causing givenInst to be a number. Since it has no classList property, calling add on undefined creates an error and terminates the loop.

To solve this, you can use isNaN to check whether the property is a number or not:

However, a better way is to use a for...of loop instead:

CodePudding user response:

You might want to prefer the for...of loop for this and make use of the spread operator. It will produce a much nicer code output:

function styleTxt() {
    let h4Elems = document.getElementsByTagName("H4");
    let pElems = document.getElementsByTagName("P");
    const elemArray = [...pElems, ...h4Elems];
    for (eachElem of elemArray) {
        eachElem.classList.add("italic");
    }
}

Of course, you can always pick both types of elements in one go with the querySelectorAll method:

const all = document.querySelectorAll("h4, p");

// Using the for...of loop:
for ( el of all ){
  el.classList.add("italic");
}

// Using the `forEach` method:
all.forEach( el => el.classList.add("italic") )

CodePudding user response:

Use Document.querySelectorAll() to get both types of elements. Iterate the NodeList with NodeList.forEach(), and add the class to each element.

function styleTxt() {
  document.querySelectorAll('h4, p')
    .forEach(el => el.classList.add('italic'));
}

styleTxt();
.italic {
  font-style: italic;
}
<h4>Text goes in here</h4>
<p>Text goes in here</p>

CodePudding user response:

Give this a try instead

<html>

<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <style>
    .italic {
      font-style: italic;
    }
  </style>
</head>

<body>
  <h4>Text goes in here</h4>
  <p>Text goes in here</p>

  <script>
    function styleTxt() {
      const h4Elems = Array.from(document.getElementsByTagName("H4"));
      const pElems = Array.from(document.getElementsByTagName("P"));
      const elemArray = [...pElems, ...h4Elems];

      elemArray.forEach(eachElem => {
        eachElem.classList.add("italic");
      })
    }

    styleTxt();
  </script>

</body>

</html>

  • Related