Dynamic body class with Angular UI-Router

后端 未结 4 660
长发绾君心
长发绾君心 2020-12-24 03:01

I\'m trying to find an elegant way to have a custom dynamically class of the body tag that I can set easily from the ui-router configurations a

相关标签:
4条回答
  • 2020-12-24 03:22

    Here's a similar approach as @jmq's using state data, but implemented as a directive instead of a controller. (The nice thing about the directive is you can apply this to any arbitrary elements)

    Example Markup

    <body ng-app="app" route-css-classnames>
    

    Routes Config (routes.js)

    $stateProvider
      .state('login', {
           url: "/login",
           template: 'Login',
           data : {
               cssClassnames : 'auth'
           }
      })
      .state('register', {
           url: "/register",
           template: 'Register',
           data : {
               cssClassnames : 'auth'
           }
      }).
      .state('profile', {
           url: "/profile",
           template: 'Profile'
      });
    

    Directive (routeCssClassnames.js)

    (function () {
        'use strict';
    
        angular.module('shared').directive('routeCssClassnames', routeCssClassnames);
    
        function routeCssClassnames($rootScope) {
            return {
                restrict: 'A',
                scope: {},
                link: function (scope, elem, attr, ctrl) {
    
                    $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
                        var fromClassnames = angular.isDefined(fromState.data) && angular.isDefined(fromState.data.cssClassnames) ? fromState.data.cssClassnames : null;
                        var toClassnames = angular.isDefined(toState.data) && angular.isDefined(toState.data.cssClassnames) ? toState.data.cssClassnames : null;
    
                        // don't do anything if they are the same
                        if (fromClassnames != toClassnames) {
                            if (fromClassnames) {
                                elem.removeClass(fromClassnames);
                            }
    
                            if (toClassnames) {
                                elem.addClass(toClassnames);
                            }
                        }
                    });
                }
            }
        }
    }());
    
    0 讨论(0)
  • 2020-12-24 03:25

    This is just a version of @JeremyWeir's directive using ui-router@1.x transition hooks.

    import angular from 'angular';
    
    class RouteCssClassNamesDirective {
      constructor($transitions) {
        this.$transitions = $transitions;
        this.restrict = 'A';
      }
    
      link(scope, element, attrs) {
        this.$transitions.onSuccess({}, (trans) => {
          const fromClassNames = angular.isDefined(trans.from().data) && angular.isDefined(trans.from().data.cssClassNames) ? trans.from().data.cssClassNames : null;
          const toClassNames = angular.isDefined(trans.to().data) && angular.isDefined(trans.to().data.cssClassNames) ? trans.to().data.cssClassNames : null;
          if (fromClassNames !== toClassNames) {
            if (fromClassNames) {
              element.removeClass(fromClassNames);
            }
            if (toClassNames) {
              element.addClass(toClassNames);
            }
          }
        });
      }
    
      static create() {
        return new RouteCssClassNamesDirective(...arguments);
      }
    
    }
    
    RouteCssClassNamesDirective.create.$inject = ['$transitions'];
    
    export default angular.module('shared')
      .directive('routeCssClassNames', RouteCssClassNamesDirective.create);
    
    0 讨论(0)
  • 2020-12-24 03:27

    You can have a master AppController that controls this:

    <html ng-app="app" ng-controller="AppController as appController">
    ...
    <body class="{{ appController.bodyClasses }}">
    

    Inside AppController:

    var vm = this;
    vm.bodyClasses = 'default';
    
    // this'll be called on every state change in the app
    $scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){
        if (angular.isDefined(toState.data.bodyClasses)) {
            vm.bodyClasses = toState.data.bodyClasses;
            return;
        }
    
        vm.bodyClasses = 'default';
    });
    

    Inside your route defs:

      .state('register', {
           url: "/register",
           template: 'Register',
           data: {
               bodyClasses: 'auth'
           }
      });
    

    See UI Router documentation for more on this data-attribute strategy.

    0 讨论(0)
  • 2020-12-24 03:29

    You could also apply this on your body tag or wherever you need it.

    ng-class="$state.current.name"
    
    0 讨论(0)
提交回复
热议问题