5

I'm building an Angular application using Angular Material. One of the first steps in the application is that the user logs in. Next, the system loads from the backend the theme made by that user's company.

However, when the backend responds with the Theme information, I am not able to get it into the system. The $mdThemingProvider, which allows you to set themes, does not seem to be available from inside a Controller and the $mdTheming service itself does not have options for modifying the themes in the system.

Is there any way to dynamically load new themes into an Angular Material application?

6 Answers 6

4

As of version 1.0.5 of angular-material:

  1. Add

    reload: generateTheme 
    

    in themingProvider function (angular-material.js line 4840 - the generateTheme function is already present in angular-material.js, we just need a way to call it)

  2. In config function:

    angular.module('my-module').config(function ($provide, $mdThemingProvider) {
     $mdThemingProvider.generateThemesOnDemand(true);
     $provide.value('themeProvider', $mdThemingProvider);});
    
  3. In your controller, inject themeProvider and now you can do something like:

    //create new theme
    themeProvider.theme('custom')
      .primaryPalette('pink')
      .accentPalette('orange')
      .backgroundPalette('yellow');
    
    //reload the theme
    themeProvider.reload('custom');
    
    //optional - set the default to this new theme
    themeProvider.setDefaultTheme('custom');
    
Sign up to request clarification or add additional context in comments.

1 Comment

reload function doesn't exist :/
3

I have managed to fix this by making some minor changes to the provider. To allow themes to be changed:

First, modify the generateThemes function in angular-material.js to set generationIsDone = false.

This will allow you to regenerate the themes at a later time.

function generateThemes($injector) {
    var styles = $injector.has('$MD_THEME_STYLESHEETS') ? $injector.get('$MD_THEME_STYLESHEETS') : [];
    if (styles) {
        var $q = $injector.get('$q');
        var $http = $injector.get('$http');
        var calls = [];

        angular.forEach(styles, function(style){
            calls.push($http.get(style));
        });

        $q.all(calls).then(function(responses) {
            var css = '';
            angular.forEach(responses, function(response) {
                css += response.data;
            });
            generationIsDone = false; // here
            generateCss(css);
        });
    } else {
        var css = $injector.has('$MD_THEME_CSS') ? $injector.get('$MD_THEME_CSS') : '';
        generationIsDone = false; // here 
        generateCss(css);
    }
}

Second, make the generateThemes() function available as a property on the ThemingService.

You can call it when you have added new themes, to generate their CSS.

  ThemingService.$inject = ["$rootScope"];
  return themingProvider = {
    definePalette: definePalette,
    extendPalette: extendPalette,
    theme: registerTheme,

    setDefaultTheme: function(theme) {
      defaultTheme = theme;
    },
    alwaysWatchTheme: function(alwaysWatch) {
      alwaysWatchTheme = alwaysWatch;
    },
    reload: generateThemes, // here
    $get: ThemingService,
    _LIGHT_DEFAULT_HUES: LIGHT_DEFAULT_HUES,
    _DARK_DEFAULT_HUES: DARK_DEFAULT_HUES,
    _PALETTES: PALETTES,
    _THEMES: THEMES,
    _parseRules: parseRules,
    _rgba: rgba
  };

Third, to actually make the ThemingProvider available to your controllers, add it to your module as a value.

angular.module("yourModule",['whateverDependencies']) .config(function($provide, $mdThemingProvider) { $provide.value('themeProvider', $mdThemingProvider); // now you can inject the provider })

And finally, where you need it, just call for the value in your controllers:

}).controller('someController', function(themeProvider, $injector) {         

 themeProvider.theme('someNewTheme').primaryColor('orange').accentColor('pink');
  themeProvider.reload($injector);
}

1 Comment

Seems like there is a new version of angular-md.js and can't seem to get this to work now
3

The following worked for me, all credit to Guilhermecvm, however I'll add the code from the Github issue in case google brings anyone else here

angular.module('app')
.config(['$mdThemingProvider', '$provide', function($mdThemingProvider, $provide) {
    $mdThemingProvider.generateThemesOnDemand(true);
    $provide.value('themeProvider', $mdThemingProvider);
}])

.controller('AppController', ['themeProvider', '$mdTheming', function(themeProvider, $mdTheming) {
    //create new theme
    themeProvider.theme('default')
      .primaryPalette('pink')
      .accentPalette('orange')
      .backgroundPalette('yellow');

    //reload the theme
    $mdTheming.generateTheme('default');

    //optional - set the default to this new theme
    themeProvider.setDefaultTheme('default');
}]);

To avoid 'attempted to use unregistered theme' warnings, the theme should be added to the mdTheming internal list of themes

var theme = themeProvider.theme...
$mdTheming.THEMES[themeName] = theme;

Comments

2

This is easier now. You only have to omit the first step. In resume:

  1. Add reload: generateThemes in themingProvider function (angular-material.js)
  2. Make the provider available to your controllers:

    $provide.value('themeProvider', $mdThemingProvider);

  3. Create your theme in your controller using themeProvider

  4. Reload themes using themeProvider.reload($injector);

Comments

0
<your_module>.config(function ($mdThemingProvider, $provide) {
     $provide.value('$mdThemingProvider', $mdThemingProvider);
});

Now you can inject $mdTheming and $mdThemingProvider in your controller and insert the code below in your controller.

$mdThemingProvider.theme(<theme_name>).primaryPalette(<primary_color>).accentPalette(>accent_color>);
$mdTheming.generateTheme(<theme_name>);

If you want this to be your default theme, then:

$mdThemingProvider.setDefaultTheme(<theme_name>);

or use md-theme="<theme_name>" in HTML.

PS: Works with Angular Material 1.1 and above.

1 Comment

I just want to know if I want to change the primaryPalette do I need to create a theme with a new name ? Cause the same name isn't working.
0

I was also having a similar scenario, CSS has provided us a feature called var(), which allows us to runtime change properties of our CSS elements. Check my blog for more details here, hope this will help you

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.