How to write an toggleClass function

JavaScript polyfill, by , Sunday, March 30th, 2014

Being able to toggle classes is very convenient in many cases in web development, so why not try to write a JavaScript method that help us do this. Most libraries have such a method, but it is always a good idea to try to write your own. It helps you understand what goes on, and how such challenges can be solved, plus it is fun to do. I am going to give you two examples of an toggleClass function, using two different approaches. Both function assume that you have the function isObjClass available in some outer scope. If you do not, have a look at my article How to get the class of an object value, you can get the function from there. The reason we need this function is, that we need a reliable way to detect if the parameters passed are of the right type. Of course you could just allow one type of parameters and you would not have to use this function, but doing that will also make the use of your function extremely limited, so lets not do that, but aim wide.

This function is very much related to the functions I have written about in the articles How to write an addClass method, How to write an removeClass method, and How to write an replaceClass function. These methods can of course be combined in creative ways, that I for now will leave to you, and you can in fact use the replaceClass function to toggle classes as well, even though that is a special case of its use So lets look at our toggleClass function instead.

Writing an toggleClass method with nested for-loop

This approach is straight forward, plainly writing the function using familiar for-loops, one nested inside the other. The outer loop will iterate over the elements passed to the function, and the inner loop will iterate over the classes to be toggled. As you have properly figured out, the function is going to take two parameters, which are as follows;

  • obj which can be a single DOM element or a collection of DOM elements.
  • cl which can be either an array of classes or a string where each class is separated by a space.

Now that we have that settled, lets have a look at the code;

  1. var toggleClass = function (obj, cl) {
  2. "use strict";
  3. var i, j,
  4. o = isObjClass(obj, 'NodeList') ? obj : [obj],
  5. oLen = o.length,
  6. cls = isObjClass(cl, 'Array') ? cl : cl.split(' '),
  7. clsLen = cls.length,
  8. targetIndex;
  9. for (i = 0; i < oLen; i += 1) {
  10. o[i].className = (function (clArr) {
  11. for (j = 0; j < clsLen; j += 1) {
  12. if ((targetIndex = clArr.indexOf(cls[j])) >= 0) {
  13. clArr.splice(targetIndex, 1);
  14. } else {
  15. clArr.push(cls[j]);
  16. }
  17. }
  18. return clArr.join(' ');
  19. }(o[i].className.split(' ')));
  20. }
  21. };

The way this function works is that we start out, at line 4, 6, by checking if our parameters are of the correct type, and if not convert them to it, such that we can use them predictably. At line 10 we iterate over the objects passed, assigning the result of the IIFE (line 11) to the current elements className property. (IIFE stands for Immediately-Invoked Functional Expression, which in other terms is a function that executes itself. Notice, that we at line 20 pass the current objects classes as an array to this function, such that it is available as the parameter clArr) From line 12 we iterate over the classes to toggle, checking at line 13 if the current class (cls[j]) is present in the objects class name array (clArr). If it is, we remove it at line 14 and if it is not, we add it at line 16. When we are done iterating over the classes, we return the classes as a string, which then gets stored in the current objects className property. Now this is just one way of writing such a function, and you might argue not the best way, so lets have a look at another.

Writing an toggleClass methods with forEach and recursion

This approach is a little more modern, taking advantage of the build in Array.prototype.forEach method. If you know, that an important part of your audience uses old browsers like IE8, then you can use a polyfill to for this method. I have written a few polyfills for the Array.prototype.forEach method, that you can use if you wish. Beside this, I also use recursion, as I believe it makes the process look much simpler. So lets have a look at the code;

  1. var toggleClass = function (obj, cl) {
  2. "use strict";
  3. var o = isObjClass(obj, 'NodeList') ? obj : [obj],
  4. cls = isObjClass(cl, 'Array') ? cl : cl.split(' ');
  5. Array.prototype.slice.call(o).forEach(function (elmVal) {
  6. elmVal.className = (function toggleCls(oClass, tIndex) {
  7. return cls[tIndex] ? toggleCls((function () {
  8. var targetIndex = oClass.indexOf(cls[tIndex]);
  9. if (targetIndex >= 0) {
  10. oClass.splice(targetIndex, 1);
  11. } else {
  12. oClass.push(cls[tIndex]);
  13. }
  14. return oClass;
  15. }()), tIndex + 1) : oClass.join(' ');
  16. }(elmVal.className.split(' '), 0));
  17. });
  18. };

In this version, line 6 might need a short explanation, so what we are doing here is turning the objects passed in, into an array, such that we have the forEach method available for use. After that, at line 7, we assign the result of the running the inline function toggleCls to the className property of the current element. The toggleCls function is passed the current elements classes as an array, plus an index number, starting with zero. At line 8 we check if we have a valid class (cls[tIndex]) and if we do we call the toggleCls function passing it the possibly modified object classes plus the incremented iterator. If on the other hand, we do not have a valid class, we return the elements classes joint as a string. Now I jumped a little bit fast over the passing of the "possibly modified object classes" part. The reason for this is, that inside the IIFE all that is happening is the same as what was happening in our previous version of this toggleClass function, i.e. we get the targetIndex, check if the class is present, if so remove it, if not add it. The only difference is, that after this we return the classes, so that they get passed as a parameter to the toggleCls function.

This is just two ways of writing such a function, if you have others, possibly better, then show me at the Boxsheep JavaScript Community. If not, you are more than welcome to use these examples in any way you want, though I would appreciate that you reference me if you choose to use them in your own articles.