Skip to content

Commit 01430ee

Browse files
committed
fix(uiSrefActive): don't match fuzzy on lazy loaded future states
1 parent b92a07c commit 01430ee

File tree

2 files changed

+82
-12
lines changed

2 files changed

+82
-12
lines changed

src/directives/stateDirectives.ts

+32-12
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ uiSrefActiveDirective = ['$state', '$stateParams', '$interpolate', '$uiRouter',
528528
restrict: 'A',
529529
controller: ['$scope', '$element', '$attrs',
530530
function ($scope: IScope, $element: IAugmentedJQuery, $attrs: any) {
531-
const states: StateData[] = [];
531+
let states: StateData[] = [];
532532
let activeEqClass: string;
533533
let uiSrefActive: any;
534534

@@ -543,15 +543,10 @@ uiSrefActiveDirective = ['$state', '$stateParams', '$interpolate', '$uiRouter',
543543
// Do nothing. uiSrefActive is not a valid expression.
544544
// Fall back to using $interpolate below
545545
}
546-
uiSrefActive = uiSrefActive || $interpolate($attrs.uiSrefActive || '', false)($scope);
547-
if (isObject(uiSrefActive)) {
548-
forEach(uiSrefActive, function (stateOrName: StateOrName, activeClass: string) {
549-
if (isString(stateOrName)) {
550-
const ref = parseStateRef(stateOrName);
551-
addState(ref.state, $scope.$eval(ref.paramExpr), activeClass);
552-
}
553-
});
546+
if (!uiSrefActive) {
547+
uiSrefActive = $interpolate($attrs.uiSrefActive || '', false)($scope);
554548
}
549+
setStatesFromDefinitionObject(uiSrefActive);
555550

556551
// Allow uiSref to communicate with uiSrefActive[Equals]
557552
this.$$addStateInfo = function (newState: string, newParams: Obj) {
@@ -568,13 +563,38 @@ uiSrefActiveDirective = ['$state', '$stateParams', '$interpolate', '$uiRouter',
568563
function updateAfterTransition(trans) {
569564
trans.promise.then(update, noop);
570565
}
571-
572-
$scope.$on('$stateChangeSuccess', update);
573-
$scope.$on('$destroy', <any> $uiRouter.transitionService.onStart({}, updateAfterTransition));
566+
$scope.$on('$destroy', setupEventListeners());
574567
if ($uiRouter.globals.transition) {
575568
updateAfterTransition($uiRouter.globals.transition);
576569
}
577570

571+
function setupEventListeners () {
572+
const deregisterStatesChangedListener = $uiRouter.stateRegistry.onStatesChanged(handleStatesChanged);
573+
const deregisterOnStartListener = $uiRouter.transitionService.onStart({}, updateAfterTransition);
574+
const deregisterStateChangeSuccessListener = $scope.$on('$stateChangeSuccess', update);
575+
return function cleanUp () {
576+
deregisterStatesChangedListener();
577+
deregisterOnStartListener();
578+
deregisterStateChangeSuccessListener();
579+
};
580+
}
581+
582+
function handleStatesChanged () {
583+
setStatesFromDefinitionObject(uiSrefActive);
584+
}
585+
586+
function setStatesFromDefinitionObject (statesDefinition: any) {
587+
if (isObject(statesDefinition)) {
588+
states = [];
589+
forEach(statesDefinition, function (stateOrName: StateOrName, activeClass: string) {
590+
if (isString(stateOrName)) {
591+
const ref = parseStateRef(stateOrName);
592+
addState(ref.state, $scope.$eval(ref.paramExpr), activeClass);
593+
}
594+
});
595+
}
596+
}
597+
578598
function addState(stateName: string, stateParams: Obj, activeClass: string) {
579599
const state = $state.get(stateName, stateContext($element));
580600

test/stateDirectivesSpec.js

+50
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,31 @@ describe('uiSrefActive', function() {
10561056
expect(a.attr('class')).toMatch(/active also-active/);
10571057
}));
10581058

1059+
it('should not match fuzzy on lazy loaded future states', inject(function($rootScope, $compile, $q, $state) {
1060+
_stateProvider.state('contacts.lazy.**', {
1061+
url: '/lazy',
1062+
lazyLoad: function() {
1063+
return $q.when().then(function() {
1064+
_stateProvider.state('contacts.lazy', {
1065+
abstract: true,
1066+
url: '/lazy'
1067+
}).state('contacts.lazy.s1', {
1068+
url: '/s1'
1069+
}).state('contacts.lazy.s2', {
1070+
url: '/s2'
1071+
});
1072+
});
1073+
}
1074+
});
1075+
template = $compile('<div ui-sref-active="active"><a ui-sref="contacts.lazy.s1">Lazy</a></div><div ui-sref-active="active"><a ui-sref="contacts.lazy.s2"></a></div>')($rootScope);
1076+
$rootScope.$digest();
1077+
$state.transitionTo('contacts.lazy.s1');
1078+
$q.flush();
1079+
timeoutFlush();
1080+
expect(template.eq(0).hasClass('active')).toBeTruthy();
1081+
expect(template.eq(1).hasClass('active')).toBeFalsy();
1082+
}));
1083+
10591084
describe('ng-{class,style} interface', function() {
10601085
it('should match on abstract states that are included by the current state', inject(function($rootScope, $compile, $state, $q) {
10611086
el = $compile('<div ui-sref-active="{active: \'admin.*\'}"><a ui-sref-active="active" ui-sref="admin.roles">Roles</a></div>')($rootScope);
@@ -1111,5 +1136,30 @@ describe('uiSrefActive', function() {
11111136
timeoutFlush();
11121137
expect(el.hasClass('active')).toBeTruthy();
11131138
}));
1139+
1140+
it('should not match fuzzy on lazy loaded future states', inject(function($rootScope, $compile, $q, $state) {
1141+
_stateProvider.state('contacts.lazy.**', {
1142+
url: '/lazy',
1143+
lazyLoad: function() {
1144+
return $q.when().then(function() {
1145+
_stateProvider.state('contacts.lazy', {
1146+
abstract: true,
1147+
url: '/lazy'
1148+
}).state('contacts.lazy.s1', {
1149+
url: '/s1'
1150+
}).state('contacts.lazy.s2', {
1151+
url: '/s2'
1152+
});
1153+
});
1154+
}
1155+
});
1156+
template = $compile('<div ui-sref-active="{ active: \'contacts.lazy.s1\' }"><a ui-sref="contacts.lazy.s1">Lazy</a></div><div ui-sref-active="{ active: \'contacts.lazy.s2\' }"></div>')($rootScope);
1157+
$rootScope.$digest();
1158+
$state.transitionTo('contacts.lazy.s1');
1159+
$q.flush();
1160+
timeoutFlush();
1161+
expect(template.eq(0).hasClass('active')).toBeTruthy();
1162+
expect(template.eq(1).hasClass('active')).toBeFalsy();
1163+
}));
11141164
});
11151165
});

0 commit comments

Comments
 (0)