0

I have a large DOM with a pre element containing thousands of span nodes with X different name attributes. Upon a user action, I'm changing the style(style.display) X-1 name attributes to none. The node count of unchanged name attribute is over 1000. But after performing this operation, the page is displaying only a couple of hundreds of unchanged instead of all.

Note: I don't see any issue when node count is low.

  function filters() {
    var nameElement = document.getElementsByName('filterType');
    let selectedFiltersList = [];
    if (nameElement.length > 0) {
      for (let i = 0; i < nameElement.length; i++) {
        if (nameElement[i].checked) {
          selectedFiltersList.push(nameElement[i].defaultValue);
        }
      }
    }
    if (selectedFiltersList.length > 0) {
    const allFilters = ["Warning", "Error", "State"];
    const unSelectedFilters = allFilters.filter(
      val => !selectedFiltersList.includes(val),
    );

    unSelectedFilters.forEach(name => {
      let nameArray = document.getElementsByName(name);
      if (
        nameArray &&
        nameArray.length > 0 &&
        nameArray[0].style.display !== 'none'
      ) {
        nameArray.forEach(elem => (elem.style.display = 'none'));
      }
    });
    } 
    }
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8" />
    <title>Viewer</title>
    <link rel="stylesheet" href="../css/view.css" />
  </head>
  <body>
    <div class="header">
      <div class="filters" onclick="filters()">
        <input type="checkbox" name="filterType" value="Warning" />
        Warning &nbsp;
        <input type="checkbox" name="filterType" value="Severe" />
        Severe &nbsp;
        <input type="checkbox" name="filterType" value="State" /> State
      </div>
    </div>
    <div class="output">
      <pre id="data">
    <span class="st" name="State"><a href="#!" title="remove line" id="1" onclick="removeLine(1)">X</a> State        ===&gt; hello state
</span>
<span class="wrn" name="Warning"><a href="#!" title="remove line" id="2" onclick="removeLine(2)">X</a> Warn        ===&gt; hello warn
</span>
<span class="err" name="Error"><a href="#!" title="remove line" id="3" onclick="removeLine(3)">X</a> Error        ===&gt;  hello error
</span>
....(// thousands of span elements like above)
    </pre>
    </div>
  </body>
</html>
jack
  • 81
  • 6
  • This sounds odd, I don't think it should occur. Can you edit a live Stack Snippet into the question that illustrates the problem, so we can see it occurring too and debug it? – CertainPerformance Aug 25 '20 at 01:03
  • What do you mean by `name` attributes? `span` elements can't have a `name` attribute. The `name` attribute is for `form` related input fields. – Scott Marcus Aug 25 '20 at 01:05
  • I also don't see the point of your entire `if` statement. `.getElementsByName()` will always return a node list, whether any nodes were found or not, so the first test of `nameArray` will never fail. The second test of `.length > 0` isn't really needed because if you attempt to loop over an empty node list/array with `.forEach()`, it just doesn't iterate, but no error is generated so no harm in trying... – Scott Marcus Aug 25 '20 at 01:10
  • ... And the third test to see if the first element in the list is not `display:none` is also really not needed because looping over all the found nodes and setting them to none, even if they already are isn't harmful either and even with thousands of nodes, the loop shouldn't hurt performance by any noticeable amount.... – Scott Marcus Aug 25 '20 at 01:12
  • ...What really is the biggest problem is your use of `.getElementsByName()`, which returns a "live node list", [which really should be avoided in most situations](https://stackoverflow.com/questions/54952088/how-to-modify-style-to-html-elements-styled-externally-with-css-using-js/54952474#54952474). – Scott Marcus Aug 25 '20 at 01:12
  • 1
    But, to answer your question, we'll need you to post the relevant HTML and CSS that goes along with the JavaScript so we can replicate your issue. – Scott Marcus Aug 25 '20 at 01:13
  • here is my code – jack Aug 25 '20 at 01:52
  • On a related, but different, note: don't touch anything in `.style` - use `element.classList.add(...)` (and related `.toggle` and `.remove` functions) to trigger CSS classes, and have already defined classes available as part of the .css file(s) you link into your HTML document. – Mike 'Pomax' Kamermans Aug 25 '20 at 03:37

1 Answers1

0

As @Mike Kamermans already commented: you should work with a class (here hide) to make targeted spans invisible. The name-attribute cannot be assigned to spans but you can use data-name instead.

Your markuo structure is still somewhat "unorthodox". I expect you will not be using <span>s in a <pre> in the finished version of the page, but the principle can be demonstrated here nonetheless.

in flt I collect the values of all checked boxes. I then loop (forEach) over all #data spans and toggle() their class hide by checking if their dataset.name can be found in flt: if they cannot be found I "hide" the element, otherwise I remove the class "hide" again.

function filters() {
  let flt=[...document.querySelectorAll('[name=filterType]:checked')].map(f=>f.value);
  [...document.querySelectorAll('#data span')].forEach(s=>
    s.classList.toggle('hide',!flt.includes(s.dataset.name)));
}
.hide {display:none}
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8" />
    <title>Viewer</title>
    <link rel="stylesheet" href="../css/view.css" />
  </head>
  <body>
    <div class="header">
      <div class="filters" onclick="filters()">
        <label><input type="checkbox" name="filterType" value="Warning" checked/>
        Warning</label> &nbsp;
        <label><input type="checkbox" name="filterType" value="Severe" checked/>
        Severe</label> &nbsp;
        <label><input type="checkbox" name="filterType" value="State" checked/> State</label>
      </div>
    </div>
    <div class="output">
<pre id="data"><span class="st" data-name="State"><a href="#!" title="remove line" id="1" onclick="removeLine(1)">X</a> State        ===&gt; hello state
</span>
<span class="wrn" data-name="Warning"><a href="#!" title="remove line" id="2" onclick="removeLine(2)">X</a> Warn        ===&gt; hello warn
</span>
<span class="err" data-name="Severe"><a href="#!" title="remove line" id="3" onclick="removeLine(3)">X</a> Error        ===&gt;  hello error
</span>
....(// thousands of span elements like above)
    </pre>
    </div>
  </body>
</html>

( I adjusted some of your span-(data-)names so they correspond with the three checkbox values. )

Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43