2

I'm trying to add/remove a class using JavaScript. (Please don't post about JQuery, because that's irrelevant.) I came upon this answer, which suggested using regular expression to remove the class. Here's the code:

function removeClass(ele, cls) {
    if (hasClass(ele, cls)) {
        var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
        ele.className = ele.className.replace(reg, ' ');
    }
}

I'm going to be adding and removing the same class. The problem is, how ever many times I do that, that's how many spaces get added to the class name. For example, if I add and remove the class 5 times, there will be 5 spaces between the 2 class names.

How can I prevent the spaces from coming?

CodePen

Code Snippet

var myDiv = document.getElementById('myDiv'),
  par = document.getElementById('par');

myDiv.addEventListener('click', function() {
  if (hasClass(myDiv, 'tryThis')) {
    removeClass(myDiv, 'tryThis');
  } else {
    addClass(myDiv, 'tryThis');
  }
  console.log(myDiv.className);
});



function hasClass(ele, cls) {
  return ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}

function addClass(ele, cls) {
  if (!hasClass(ele, cls)) ele.className += " " + cls;
}

function removeClass(ele, cls) {
  if (hasClass(ele, cls)) {
    var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
    ele.className = ele.className.replace(reg, ' ');
  }
}
#myDiv {
  width: 100px;
  height: 100px;
  background-color: green;
}
.tryThis {
  border: 2px solid orange;
}
<div id="myDiv" class="hello">Click Me</div>
<p id="par"></p>

4
  • 3
    Modern browsers have this built in. developer.mozilla.org/en-US/docs/Web/API/Element/classList and look at the polyfill to see how they handle removing classes. Commented Jan 25, 2016 at 1:32
  • would that RegExp work on a class like a-z? Commented Jan 25, 2016 at 1:33
  • @epascarello But I want to support older browsers as well. Commented Jan 25, 2016 at 1:39
  • 1
    That is why there is a polyfill. It adds support for the older browsers... Commented Jan 25, 2016 at 1:40

4 Answers 4

3

There's two solutions. The first (and easiest) is to use classList. The only downfall to this solution is that you won't be able to keep support for browsers that are older than its implementation.

As for the second solution, which keeps support for old browsers and extends off your regex solution, I'd suggest passing a function to replace that checks if both sides of the class name are whitespace. If they are, return ' ' otherwise return ''.

function removeClass(ele, cls) {
  if (hasClass(ele, cls)) {
    var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
    ele.className = ele.className.replace(reg, function(match) {
      if (match.match(/^\s.+\s$/) !== null) {
        return ' ';
      } else {
        return '';
      }
    });
  }
}

Edit: There's also the option of using a shim, sham, shiv, polyfill, etc.

Sign up to request clarification or add additional context in comments.

Comments

0

Why dont you use classList instead:

var ele = document.getElementByID("myDiv");
if(ele.classList.contains("tryThis")){
  ele.classList.remove("tryThis");
}else{
  ele.classList.add("tryThis");
}

Reference : http://callmenick.com/post/add-remove-classes-with-javascript-property-classlist

3 Comments

Old browser support. Your solution is valid, if not for those pesky oldies.
@Everesty there is a shim that gives support to IE8 and up and also is cross browser... Kindly check the edited link in the solution.
Sure, but that's practically the same as saying "just use jquery;" it doesn't actually answer the question while still being a valid solution. I will, however, agree that using a polyfill or shim is a good idea and should be taken up if it'll prove useful.
0

It looks like if you add trim to the replace statement it's working, so change it to this: ele.className = ele.className.replace(reg, ' ').trim(); Although trim() doesn't work in IE8, so if that's an issue, this isn't a satisfactory solution. Hope this helps.

Best!

2 Comments

But if the class name is in the middle of a list you suddenly join two classnames.
Ah, yes good point. What about just simply adding .trim() to the replace statement?
0

Regex is dangerous!*

(* Hah, I'm only kidding!)

If you're looking for a super naive and inefficient solution to this problem, this is what I've come up with. I basically replace what's happening inside your functions by using a number of methods for strings and arrays (.indexOf, .split, .join, etc).

Obviously, this is suboptimal, since the time complexity is going to be linear (at least I think it's linear, since we're iterating over an array a bunch of times).

function hasClass(ele, cls) {
   // Check that our string contains the class name.
   return (ele.className.indexOf(cls) >= 0);
}

function addClass(ele, cls) {
  if (!hasClass(ele, cls)) {
    var classArray = ele.className.split(' ');
    classArray.push(cls);
    ele.className = classArray.join(' ');
  }
}

function removeClass(ele, cls) {
  if (hasClass(ele, cls)) {
    var classArray = ele.className.split(' ');
    var classLocation = classArray.indexOf(cls);
    classArray.splice(classLocation,1);
    ele.className = classArray.join(' ')
  }
}

1 Comment

This implementation of hasClass is very dangerous.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.