diff --git a/src/stateDirectives.js b/src/stateDirectives.js
index b39f7b6c8..eb7accb5d 100644
--- a/src/stateDirectives.js
+++ b/src/stateDirectives.js
@@ -173,12 +173,17 @@ function $StateRefDynamicDirective($state, $timeout) {
var group = [attrs.uiState, attrs.uiStateParams || null, attrs.uiStateOpts || null];
var watch = '[' + group.map(function(val) { return val || 'null'; }).join(', ') + ']';
var def = { state: null, params: null, options: null, href: null };
+ var unlinkInfoFn = null;
function runStateRefLink (group) {
def.state = group[0]; def.params = group[1]; def.options = group[2];
def.href = $state.href(def.state, def.params, def.options);
- if (active) active.$$addStateInfo(def.state, def.params);
+ if (unlinkInfoFn) {
+ unlinkInfoFn();
+ unlinkInfoFn = null;
+ }
+ if (active) unlinkInfoFn = active.$$addStateInfo(def.state, def.params);
if (def.href) attrs.$set(type.attr, def.href);
}
@@ -319,8 +324,9 @@ function $StateRefActiveDirective($state, $stateParams, $interpolate) {
if (isObject(uiSrefActive) && states.length > 0) {
return;
}
- addState(newState, newParams, uiSrefActive);
+ var deregister = addState(newState, newParams, uiSrefActive);
update();
+ return deregister;
};
$scope.$on('$stateChangeSuccess', update);
@@ -329,13 +335,19 @@ function $StateRefActiveDirective($state, $stateParams, $interpolate) {
var state = $state.get(stateName, stateContext($element));
var stateHash = createStateHash(stateName, stateParams);
- states.push({
+ var stateInfo = {
state: state || { name: stateName },
params: stateParams,
hash: stateHash
- });
+ };
+ states.push(stateInfo);
activeClasses[stateHash] = activeClass;
+
+ return function removeState() {
+ var idx = states.indexOf(stateInfo);
+ if (idx !== -1) states.splice(idx, 1);
+ };
}
/**
diff --git a/test/stateDirectivesSpec.js b/test/stateDirectivesSpec.js
index a9c0f120f..977b878f1 100644
--- a/test/stateDirectivesSpec.js
+++ b/test/stateDirectivesSpec.js
@@ -292,10 +292,11 @@ describe('uiStateRef', function() {
});
describe('links with dynamic state definitions', function () {
- var template;
+ var template, $state;
- beforeEach(inject(function($rootScope, $compile, $state) {
- el = angular.element('state');
+ beforeEach(inject(function($rootScope, $compile, _$state_) {
+ $state = _$state_;
+ el = angular.element('state');
scope = $rootScope;
angular.extend(scope, { state: 'contacts', params: {} });
template = $compile(el)(scope);
@@ -326,6 +327,38 @@ describe('uiStateRef', function() {
expect(angular.element(template[0]).attr('href')).toBe('#/contacts');
});
+ it('updates a linked ui-sref-active', inject(function ($timeout) {
+ function tick() { scope.$digest(); try { $timeout.flush(); } catch (error) { } }
+ expect(template[0].className).not.toContain('active');
+ expect(template[0].className).not.toContain('activeeq');
+
+ $state.go('contacts');
+ tick();
+ expect(template[0].className).toContain('active activeeq');
+
+ scope.state = 'contacts.item';
+ scope.params = { id: 5 };
+ tick();
+ expect(template[0].className).not.toContain('active');
+ expect(template[0].className).not.toContain('activeeq');
+
+ $state.go('contacts.item', { id: -5 });
+ tick();
+ expect(template[0].className).not.toContain('active');
+ expect(template[0].className).not.toContain('activeeq');
+
+ $state.go('contacts.item', { id: 5 });
+ tick();
+ expect(template[0].className).toContain('active activeeq');
+
+ scope.state = 'contacts';
+ scope.params = { };
+ tick();
+ expect(template[0].className).toContain('active');
+ expect(template[0].className).not.toContain('activeeq');
+
+ }));
+
it('accepts param overrides', inject(function ($compile) {
el = angular.element('state');
scope.state = 'contacts.item';