Skip to content

Instantly share code, notes, and snippets.

@kentbrew
Last active September 11, 2017 01:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kentbrew/b0f5d0ecf917ed6b48f761c287bd0f84 to your computer and use it in GitHub Desktop.
Save kentbrew/b0f5d0ecf917ed6b48f761c287bd0f84 to your computer and use it in GitHub Desktop.
Towards A Modernized JavaScript Class Name Changer

Towards A Modernized JavaScript Class Name Changer

Previously we'd do something horrible with string matching when we wanted to change an HTML element's class name with JavaScript.

var changeClass = function (el, add, remove) {
  if (el) {

    if (!el.className) {
      el.className = '';
    }
    
    // replace in existing class
    if (remove && remove.length) {
      for (var i = 0, n = remove.length; i < n; i = i + 1) {
        el.className.replace(new RegExp('(?:^|\\s)'+ remove[i] + '(?:\\s|$)', 'g'), ' ');
      }
    }
    
    // strip and minimize whitespace
    el.className = el.className.replace(s/^\s+|\s+$|\s+(?=\s)//g);

    // add new stuff to the back
    if (add && add.length) {
      for (var i = 0, n = add.length; i < n; i = i + 1) {
        el.className = el.className + ' ' + add[i];
      }
    }
  }
};

Since classList Landed in Modern Browsers

// takes an element and two optional lists, one to add and one to remove
var changeClass = o => {
  if (o.el) {
    o.el.classList.add.apply(o.el.classList, o.add);  
    o.el.classList.remove.apply(o.el.classList, o.remove);
  }
};

What's Going On Here?

All fuctions have call and apply methods built in at the Function.prototype level. Here we're using apply because we want to run through the array of arguments we sent in o.add and o.remove. Explained here:

http://adripofjavascript.com/blog/drips/invoking-javascript-functions-with-call-and-apply.html

Um ... "modern browsers?"

Pretty much anything you should care about. See CanIUse for details:

http://caniuse.com/#search=classlist

Some Results

<a id="foo" class="bar baz">Hit Me</a>
var foo = document.getElementById('foo');

Add

changeClass({el: foo, 'add': ['baz']});

Result

<a id="foo" class="bar baz">Hit Me</a>

Remove

changeClass({el: foo, 'remove': ['bar']});

Result

<a id="foo" class="baz">Hit Me</a>

Do Nothing

changeClass({el: foo});

Result

<a id="foo" class="baz">Hit Me</a>

This works because apply is smart enough to do nothing with null or undefined, and is the reason why we don't have to explictly test for the presence of add or remove arrays before firing it off.

foo.classList.add.apply(foo.classList, null);

Complex Maneuvers

changeClass({el: foo, 'add': ['woo', 'yay'], 'remove': ['baz']});

Result

<a id="foo" class="woo yay">Hit Me</a>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment