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];
}
}
}
};
// 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);
}
};
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
Pretty much anything you should care about. See CanIUse for details:
http://caniuse.com/#search=classlist
<a id="foo" class="bar baz">Hit Me</a>
var foo = document.getElementById('foo');
changeClass({el: foo, 'add': ['baz']});
<a id="foo" class="bar baz">Hit Me</a>
changeClass({el: foo, 'remove': ['bar']});
<a id="foo" class="baz">Hit Me</a>
changeClass({el: foo});
<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);
changeClass({el: foo, 'add': ['woo', 'yay'], 'remove': ['baz']});
<a id="foo" class="woo yay">Hit Me</a>