Changing class properties dynamically

If you have settings in an app that can be changed dynamically (for example background colors) during use, then it can be tricky to do that without applying the specific styles to each affected element. Applying classes is better, but that would mean knowing  and setting up all the class properties in advance, which you cant do if you are allowing user customization.

I had read plenty of posts on stackoverflow to see how to instead just modify the class dynamically but I couldn't find a simple way to do it, especially where I also wanted to adjust selectors like :hover. I did see plenty of people saying 'why would you want to do that' and some of the usual SO commentary, but it seems like a very legit thing to do as far as I can see - so I'm going to do it anyway.

Example

Let's say that you want to change the definition of a class from

.emergency {
  background-color:orange;
}

to 

.emergency {
  background-color:red;
}

So that all the elements with that class applied change background-color.  One way would be to find all the elements with that class, and set their style to override the value applied from the style sheet. 

element.style.backgroundColor = "red";

But if you could just simply change what the style meant, it would be a lot more useful

I'm not an expert with css, but here's a method that seems to work fine, and in the end it's not all that complicated.  You can use it like this to change any property in any class.
DomUtils.classPatch("emergency", "background-color", "red");
        
// selectors can be patched too
DomUtils.classPatch("emergency:hover", "background-color", "orange");

Here's the code
  var DomUtils = (function(ns) {
    ns.classPatch = function(className, property, newValue) {

      // get the known styles and make any changes
      ns.getQuery("style").forEach(function(d) {
        var rxs = '([\\s\\S]*\\.' + className + '\\s*{[\\s\\S]*?' + property + '[\\s]*?:[\\s]*?)([\\w#]+)([\\s\\S]*)';
        var rx = new RegExp(rxs, "mig");
        if (d.innerHTML.match(rx)) {
          d.innerHTML = d.innerHTML.replace(rx, "$1" + newValue + "$3");
        }
      });
    };

    ns.getQuery = function(selector) {

      return [].map.call(document.querySelectorAll(selector), function(d) {
        return d;
      });
    };

    return ns;
  })(DomUtils || {});


Demo

See this codepen to try it out

For more like this, see Google Apps Scripts snippets. Why not join our forumfollow the blog or follow me on twitter to ensure you get updates when they are available. 



Comments