diff --git a/src/directives/stateDirectives.ts b/src/directives/stateDirectives.ts index 78e67d552..0e498dbc1 100644 --- a/src/directives/stateDirectives.ts +++ b/src/directives/stateDirectives.ts @@ -528,7 +528,7 @@ uiSrefActiveDirective = ['$state', '$stateParams', '$interpolate', '$uiRouter', restrict: 'A', controller: ['$scope', '$element', '$attrs', function ($scope: IScope, $element: IAugmentedJQuery, $attrs: any) { - const states: StateData[] = []; + let states: StateData[] = []; let activeEqClass: string; let uiSrefActive: any; @@ -543,15 +543,10 @@ uiSrefActiveDirective = ['$state', '$stateParams', '$interpolate', '$uiRouter', // Do nothing. uiSrefActive is not a valid expression. // Fall back to using $interpolate below } - uiSrefActive = uiSrefActive || $interpolate($attrs.uiSrefActive || '', false)($scope); - if (isObject(uiSrefActive)) { - forEach(uiSrefActive, function (stateOrName: StateOrName, activeClass: string) { - if (isString(stateOrName)) { - const ref = parseStateRef(stateOrName); - addState(ref.state, $scope.$eval(ref.paramExpr), activeClass); - } - }); + if (!uiSrefActive) { + uiSrefActive = $interpolate($attrs.uiSrefActive || '', false)($scope); } + setStatesFromDefinitionObject(uiSrefActive); // Allow uiSref to communicate with uiSrefActive[Equals] this.$$addStateInfo = function (newState: string, newParams: Obj) { @@ -568,13 +563,38 @@ uiSrefActiveDirective = ['$state', '$stateParams', '$interpolate', '$uiRouter', function updateAfterTransition(trans) { trans.promise.then(update, noop); } - - $scope.$on('$stateChangeSuccess', update); - $scope.$on('$destroy', $uiRouter.transitionService.onStart({}, updateAfterTransition)); + $scope.$on('$destroy', setupEventListeners()); if ($uiRouter.globals.transition) { updateAfterTransition($uiRouter.globals.transition); } + function setupEventListeners () { + const deregisterStatesChangedListener = $uiRouter.stateRegistry.onStatesChanged(handleStatesChanged); + const deregisterOnStartListener = $uiRouter.transitionService.onStart({}, updateAfterTransition); + const deregisterStateChangeSuccessListener = $scope.$on('$stateChangeSuccess', update); + return function cleanUp () { + deregisterStatesChangedListener(); + deregisterOnStartListener(); + deregisterStateChangeSuccessListener(); + }; + } + + function handleStatesChanged () { + setStatesFromDefinitionObject(uiSrefActive); + } + + function setStatesFromDefinitionObject (statesDefinition: any) { + if (isObject(statesDefinition)) { + states = []; + forEach(statesDefinition, function (stateOrName: StateOrName, activeClass: string) { + if (isString(stateOrName)) { + const ref = parseStateRef(stateOrName); + addState(ref.state, $scope.$eval(ref.paramExpr), activeClass); + } + }); + } + } + function addState(stateName: string, stateParams: Obj, activeClass: string) { const state = $state.get(stateName, stateContext($element)); diff --git a/test/stateDirectivesSpec.js b/test/stateDirectivesSpec.js index 5c4bb3f17..2c66bbb3a 100644 --- a/test/stateDirectivesSpec.js +++ b/test/stateDirectivesSpec.js @@ -1056,6 +1056,31 @@ describe('uiSrefActive', function() { expect(a.attr('class')).toMatch(/active also-active/); })); + it('should not match fuzzy on lazy loaded future states', inject(function($rootScope, $compile, $q, $state) { + _stateProvider.state('contacts.lazy.**', { + url: '/lazy', + lazyLoad: function() { + return $q.when().then(function() { + _stateProvider.state('contacts.lazy', { + abstract: true, + url: '/lazy' + }).state('contacts.lazy.s1', { + url: '/s1' + }).state('contacts.lazy.s2', { + url: '/s2' + }); + }); + } + }); + template = $compile('
Lazy
')($rootScope); + $rootScope.$digest(); + $state.transitionTo('contacts.lazy.s1'); + $q.flush(); + timeoutFlush(); + expect(template.eq(0).hasClass('active')).toBeTruthy(); + expect(template.eq(1).hasClass('active')).toBeFalsy(); + })); + describe('ng-{class,style} interface', function() { it('should match on abstract states that are included by the current state', inject(function($rootScope, $compile, $state, $q) { el = $compile('
Roles
')($rootScope); @@ -1111,5 +1136,30 @@ describe('uiSrefActive', function() { timeoutFlush(); expect(el.hasClass('active')).toBeTruthy(); })); + + it('should not match fuzzy on lazy loaded future states', inject(function($rootScope, $compile, $q, $state) { + _stateProvider.state('contacts.lazy.**', { + url: '/lazy', + lazyLoad: function() { + return $q.when().then(function() { + _stateProvider.state('contacts.lazy', { + abstract: true, + url: '/lazy' + }).state('contacts.lazy.s1', { + url: '/s1' + }).state('contacts.lazy.s2', { + url: '/s2' + }); + }); + } + }); + template = $compile('
Lazy
')($rootScope); + $rootScope.$digest(); + $state.transitionTo('contacts.lazy.s1'); + $q.flush(); + timeoutFlush(); + expect(template.eq(0).hasClass('active')).toBeTruthy(); + expect(template.eq(1).hasClass('active')).toBeFalsy(); + })); }); });