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>