A solution for two-binding between angular and a style sheet

All we need is an easy explanation of the problem, so here it is.

I know this sounds silly but I’m writing a wysiwyg editor that allows Designers to create style guides. I’ve become very fascinated with 2 way binding in angular and was curious if it was possible to two-way bind between a css sheet and a ng-model input field. Currently, I’m making a dynamic style guide that allows a designer to colorpick a primary, secondary colors of a page. These color will change the entire theme of the site uniformly and it would be awesome to do this from the stylesheet itself.

HTML

<input type="text" ng-model="color.primary" />
<button class="btn primary-color" />

CSS

.primary-color {
  background: {{color.primary}};
}

js
$scope.color {primary: ’00f’, secondary: ‘#e58’}

I know there are plenty of directives like ng-style and ng-class But I fear that every tag will have to be a directive because everything could have an ng-style/ng-class tag. Thus making my code not very dry and hard to maintain.

What if I wanted a dynamic style guide of css. A sheet that I could store as key value pairs of CSS into server like firebase, perhaps even 3way bind the changing of colors in real time? I’m pretty sure this cannot be accomplished using solely angular… would anyone have any ideas on pre compilers or hacks to accomplish this task so that it would result in one clean style guy?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

This was pretty fun to work on.

You have access to all of the styles on a page through document.styleSheets, so you just need scope the rules on a style. So lets say that I have this class:

.class {
    font-size: 20px;
    color: blue;
}

How jsfiddle implements sheets, this is the third style sheet added to the document, so I can just assign to the scope like this:

myApp.controller('TestController', ['$scope', function ($scope) {
    $scope.styles = document.styleSheets[3].rules;     
}]); 

This would let you do things like $scope.styles[0].style['color'] = 'red' to change the color of anything with class to red. Since it’s the first thing in the style array.

But that’s not cool enough, so we want to create a directive where we can change these from a ui. So we’d like to know all of the things that class controls, to create controls for them, So we can manipulate the css string to get all of those.

Next we have to create a temporary scoped object on the directive that starts off with all of the styles. The reason is that style sheets have checking, so as you type into an input if you do something like $scope.styles[0].style['color'] = 'g' and it was red, it will just reset to red.

So we create an input for each style type, with ng-model of our temp, then just listen for changes and attempt to assign to the style sheet.

I created a fiddle where I implement it, but the directive looks like this.

myApp.directive('styler', function() {
    return {
        scope: {
            styles: '='
        },
        restrict: 'EA',
        template: '<div ng-repeat="type in types">{{type}} <input ng-change="Change(type)" ng-model="temp_styles[type]"/></div>',
        link: function(scope, elt, attrs) {      
            // get the actual styles
            var types = scope.styles.cssText.replace(/ /g, '').split('{')[1].split('}')[0].split(';');
            scope.types = [];
            scope.temp_styles = {};
            // get rid of "" element at the end
            types.pop();
            for (var i in types) {
                var split = types[i].split(':');
                scope.types.push(split[0]);
                scope.temp_styles[split[0]] = split[1];
            }
            scope.Change = function(type) {
                scope.styles.style[type] = scope.temp_styles[type];
            };
        }
    };
});

Cool, dynamic two way binding of styles!

Hope this helped!

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply