21

I found the following regex from another Stack Overflow question: Change an element's class with JavaScript

And have used it in part of my script with success, however in another it seems to be failing.

I threw together a very minimalist test case on jsFiddle, and it is also failing:

http://jsfiddle.net/ew47Y/1/

HTML:

<div class="foo" id="foo">
    hello
</div>​

JS:

$(document).ready(function(){
     foo = document.getElementById('foo');
     foo.className += ' bar foobar';
     alert(foo.className);
     foo.className.replace( /(?:^|\s)bar(?!\S)/ , '' )
     alert(foo.className);
})​
Community
  • 1
  • 1
Chris Sobolewski
  • 12,819
  • 12
  • 63
  • 96

4 Answers4

41

That's because replace doesn't actually modify the string you call it on; rather, it returns a new string. So:

     foo.className = foo.className.replace( /(?:^|\s)bar(?!\S)/ , '' )

(By the way, you don't actually need to do this in raw JavaScript, since jQuery objects offer a removeClass method: http://api.jquery.com/removeClass/. So you could write:

     $('#foo').removeClass('bar');

or:

     $(foo).removeClass('bar');

)

ruakh
  • 175,680
  • 26
  • 273
  • 307
  • 15
    Pure JS function: `function removeClass(e,c) {e.className = e.className.replace( new RegExp('(?:^|\\s)'+c+'(?!\\S)') ,'');}` – pawelglow Jan 17 '13 at 15:18
  • If you want to remove all the occurrences of a class name use the [`g` modifier](http://www.w3schools.com/jsref/jsref_regexp_g.asp) at the end of the regular expression, like this: `foo.className.replace(/(^|\s)bar(?!\S)/g ,'')`. By the way, the use of the [non-capturing group](http://www.regular-expressions.info/refadv.html) `(?:)` is not neccessary here. – Adam Jun 03 '13 at 14:33
  • 1
    Note that the use of the [word boundary metacharacter `\b`](http://www.regular-expressions.info/wordboundaries.html), like: `foo.className.replace(/\bbar\b/g ,'')`, is not suitable here, because the word boundary occurs also between a word character `[A-Za-z0-9_]` and the dash `-` character. Therefore a class name e.g. *'different-bar-class'* would also be replaced resulting in *'different--class'*. However, as opposed to the above solutions, the "`\b`" solution doesn't remove the whitespace character `\s` before the class name, so a string e.g. *'firstbar bar'* will end up as *'firstbar '*. – Adam Jun 03 '13 at 15:41
  • 1
    @Adam: I have no idea what you're talking about. Your comment is the only place on this page that even mentions `\b`, so you hardly need to explain why it's inappropriate. And the use of a group *is* necessary; your personal preference for capturing groups `(...)` over non-capturing groups `(?:...)` is not of interest to anyone else. – ruakh Jun 03 '13 at 17:20
  • Sorry for the confusion. I mainly meant to point out that the solution above (as opposed to the also possible "`\b`" solution) removes the whitespace which could be unwanted. I have rewritten this as an answer. We can now delete these last 3 superfluous comments here. – Adam Aug 08 '13 at 12:13
  • 1
    The double negation in the look-ahead `(?!\S)` seems unnecessary. I would rather use `(?=\s|$)`, seems clearer. – doABarrelRoll721 Feb 17 '16 at 14:08
22

Don't forget about classList.

el.classList.remove('boop');

http://jsfiddle.net/yXQL3/

Derek Reynolds
  • 3,473
  • 3
  • 25
  • 34
6
foo.className = foo.className.replace( /(?:^|\s)bar(?!\S)/ , '' );

or with jQuery (which you seem to be using):

foo.removeClass( 'bar' );
1

There is also a solution which use the word boundary metacharacter \b:

foo.className.replace(/\bbar\b/g ,'');

This can suite somebody, but be aware the word boundary occurs also between a word character [A-Za-z0-9_] and the dash - character. Therefore a class name e.g. 'different-bar-class' would also be replaced resulting in 'different--class'. However, as opposed to the above solutions, the "\b" solution doesn't remove the whitespace character \s before the class name, which may be desired, so a string e.g. 'firstbar bar' will end up as 'firstbar '.

Adam
  • 1,926
  • 23
  • 21