0

I would like to remove all classes starting with nf-

Console image

JSfiddle https://jsfiddle.net/zapjelly/fda3Lm84/11/

I have the following HTML/JS:

var nfClasses = document.querySelectorAll('.custom-nf [class*="nf-"]');

Array.prototype.map.call(nfClasses, function(elem) {
  Array.prototype.map.call(elem.classList, function(classStr) {
    if (classStr.match(/^nf\-/)) elem.classList.remove(classStr);
  });
});
<p>Remember to inspect element on the input below</p>
<div class="custom-nf">
  <div class="input nf-input-outer nf-validation">
    <div class="nf-container">
      <div class="nf-outer nf-outer-input nf-outer-validation">
        <div class="nf-middle">
          <div class="nf-inner">
            <label for="dummy" class="nf-label"></label>
            <input id="dummy" type="text" class="nf-input">
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
zapjelly
  • 75
  • 4
  • querySelectorAll is not collecting the classes you required, Try the fix there to select the required classes – Aravindhan Jan 21 '16 at 03:38
  • @PatrickEvans I don't think that's a duplicate. The OP is trying to remove specific *classes* from an element. They are not trying to remove elements like in the duplicate. – Josh Crozier Jan 21 '16 at 03:49

2 Answers2

1

As stated by MDN, the .classList property returns a live DOMTokenList of the class attributes of the element. The key point is that the list is live, which means that as you remove classes, you are inadvertently skipping over some of the other classes while iterating over them.

Based on the code that you provided, you could simply create a copy of the class list so that it is no longer live. You can do this by calling the .slice() method:

Updated Example

var nfClasses = document.querySelectorAll('.custom-nf [class*="nf-"]');
Array.prototype.forEach.call(nfClasses, function(element) {
  var classListCopy = Array.prototype.slice.call(element.classList);
  classListCopy.forEach(function(className) {
    if (className.match(/^nf\-/)) {
      element.classList.remove(className);
    }
  });
});

Alternatively, you could also iterate over the classes backwards. In doing so, none of the classes will be skipped:

Updated Example

var nfClasses = document.querySelectorAll('.custom-nf [class*="nf-"]');
Array.prototype.forEach.call(nfClasses, function(element) {
  for (var i = element.classList.length; i >= 0; i--) {
    if (element.classList[i] && element.classList[i].match(/^nf\-/)) {
      element.classList.remove(element.classList[i]);
    }
  }
});

A third option would be to just use a regular expression to replace the classes:

var nfClasses = document.querySelectorAll('.custom-nf [class*="nf-"]');
Array.prototype.forEach.call(nfClasses, function(element) {
  element.className = element.className.replace(/\bnf-\S+\b/g, '').trim();
});
Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
0

Updated inner loop to slice as suggested and working now

https://jsfiddle.net/zapjelly/fda3Lm84/12/

var nfClasses = document.querySelectorAll('.custom-nf [class*="nf-"]');

Array.prototype.map.call(nfClasses,
    function(elem){
    Array.prototype.slice.call(elem.classList).map(
        function(classStr){
            if(classStr.match(/^nf\-/)) elem.classList.remove(classStr);
        })
  });
zapjelly
  • 75
  • 4