11

I'm currently building an app that has the option to change the theme. A theme in this instance, simply consists of changing the color of a few key elements in the app.

So currently, on all elements that require the theme color, I have given them the css class has-main-color.

In the controller, I get their desired color from the web service and set it to the scope as $scope.mainColor = color;.

All of this works fine, but the problem I'm getting is that I can't find a suitable method of applying this color to the has-main-color class.

Currently, I'm trying the following:

<style>
    .has-main-color {
        color: {{mainColor}}
    }
</style>

As you could probably guess, this doesn't work so well.

So what would be the best approach to solve this problem using AngularJS?

Léo Lam
  • 3,870
  • 4
  • 34
  • 44
Sam
  • 1,315
  • 2
  • 13
  • 27
  • 3
    styles inside the get applied only once. So changing the content inside of it dynamically doesnt help. – ganaraj Mar 22 '13 at 15:04

3 Answers3

10

Look at the documentation page for ngStyle. It has almost exactly what you want.

<input type="button" value="set" ng-click="myStyle={color:'red'}">
<input type="button" value="clear" ng-click="myStyle={}">
<br/>
<span ng-style="myStyle">Sample Text</span>
<pre>myStyle={{myStyle}}</pre>
Ryan O'Neill
  • 3,727
  • 22
  • 27
  • I've done a bit of research into ng-style, and it turns out this is exactly what I need. Thank you for your assistance – Sam Mar 28 '13 at 01:51
  • @Ryan, will it work if I receive the css styles from my Drupal APIs? Suppose i have an app for different group of people an dbased on that user's branding, i need to change, css color, font etc. – Smitha May 04 '16 at 14:03
7

I don't think you can use a class to do this, however try this

<div ng-app="test-app" ng-controller="MyController" theme-wrapper="{{mainColor}}">
    <div class="has-main-color">Top1</div>
    <div>Child 1</div>
    <div class="has-main-color">Top1</div>
    <div>Child 1</div>
    <div class="has-main-color">Top1</div>
    <div>Child 1</div>
    <br />
    <input type="button" value="Red" ng-click="color('red')" />
    <input type="button" value="Green" ng-click="color('green')" />
    <input type="button" value="Blue" ng-click="color('blue')" />
</div>

JS

var app = angular.module('test-app', []);

app.controller('MyController', function($scope, $rootScope, $timeout){
    $scope.mainColor = 'grey';
    $scope.color = function(color) {
        $scope.mainColor = color;
    }
});

app.directive('themeWrapper', function(){
    var counter = 0, regex = /^theme-wrapper-\d+$/;
    return {
        restrict: 'A',
        link: function(scope, elm, attrs){
            attrs.$observe('themeWrapper', function(value){
                var className = 'theme-wrapper-' + (counter++);
                $('<style>.' + className + ' .has-main-color{color: ' + value + ';}</style>').appendTo('head');

                var classes = elm.attr('class').split(' ');
                angular.forEach(classes, function(v, i){
                    if(regex.test(v)) {
                        elm.removeClass(v);
                    }
                });

                elm.addClass(className);
            });
        }
    }
});

Demo: Fiddle

Another easy fix

<div ng-app="test-app" ng-controller="MyController">
    <div style="color: {{mainColor}}">Top1</div>
    <div>Child 1</div>
    <div style="color: {{mainColor}}">Top1</div>
    <div>Child 1</div>
    <div style="color: {{mainColor}}">Top1</div>
    <div>Child 1</div>
    <br />
    <input type="button" value="Red" ng-click="color('red')" />
    <input type="button" value="Green" ng-click="color('green')" />
    <input type="button" value="Blue" ng-click="color('blue')" />
</div>

JS

var app = angular.module('test-app', []);

app.controller('MyController', function($scope, $rootScope, $timeout){
    $scope.mainColor = 'grey';
    $scope.color = function(color) {
        $scope.mainColor = color;
    }
})

Demo: Fiddle

Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
7

If anyone would like to use your original approach, I came across the same problem today and threw together a (tiny!) directive for style which allows for angular expressions inside inline style sheets.

https://github.com/deanmcpherson/angular-inline-style

Allows for

body { background-color: {{bgColor}}; }

With bg color attached to the appropriate scope.

deanmcpherson
  • 738
  • 5
  • 8
  • Heh, nice work! For the last 3+ months I've been doing the same thing so it might be worth a look-see: [ngCss](http://opensourcetaekwondo.com/ngcss) / [on GitHub](https://github.com/campbeln/ngCss). The issue I see with yours is needing to be within a scope for it to work (so either having the `ng-controller` on the HTML tag or having the STYLE in-line). But then again, yours is 13 lines of code while mine has recently crept past 650 lines ;) – Campbeln Jan 21 '15 at 02:39
  • @deanmcpherson, Simple and clean! Thank you for sharing! – Jim Harkins Oct 02 '15 at 14:27
  • Found this which does not require a custom directive. http://stackoverflow.com/a/29309120/3291253 – Jim Harkins Oct 02 '15 at 18:47