Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically loading a material theme in angular

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?

like image 260
Erik Avatar asked Feb 19 '15 09:02

Erik


2 Answers

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');
    
like image 118
stonecat Avatar answered Oct 10 '22 04:10

stonecat


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);
}
like image 34
Erik Avatar answered Oct 10 '22 03:10

Erik