Skip to content

Commit e13988b

Browse files
fix(uiView): Fixed infinite loop when is called .go() from a controller. Closes #1194
1 parent b92211d commit e13988b

File tree

2 files changed

+59
-12
lines changed

2 files changed

+59
-12
lines changed

src/viewDirective.js

+12-12
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,11 @@ function $ViewDirective( $state, $injector, $uiViewScroll) {
203203

204204
function updateView(firstTime) {
205205
var newScope = scope.$new(),
206-
name = currentEl && currentEl.data('$uiViewName'),
206+
name = getUiViewName(attrs, $element.inheritedData('$uiView')),
207207
previousLocals = name && $state.$current && $state.$current.locals[name];
208208

209209
if (!firstTime && previousLocals === latestLocals) return; // nothing to do
210+
latestLocals = $state.$current.locals[name];
210211

211212
var clone = $transclude(newScope, function(clone) {
212213
renderer.enter(clone, $element, function onUiViewEnter() {
@@ -217,8 +218,6 @@ function $ViewDirective( $state, $injector, $uiViewScroll) {
217218
cleanupLastView();
218219
});
219220

220-
latestLocals = $state.$current.locals[clone.data('$uiViewName')];
221-
222221
currentEl = clone;
223222
currentScope = newScope;
224223
/**
@@ -249,16 +248,8 @@ function $ViewDirectiveFill ($compile, $controller, $state) {
249248
compile: function (tElement) {
250249
var initial = tElement.html();
251250
return function (scope, $element, attrs) {
252-
var name = attrs.uiView || attrs.name || '',
253-
inherited = $element.inheritedData('$uiView');
254-
255-
if (name.indexOf('@') < 0) {
256-
name = name + '@' + (inherited ? inherited.state.name : '');
257-
}
258-
259-
$element.data('$uiViewName', name);
260-
261251
var current = $state.$current,
252+
name = getUiViewName(attrs, $element.inheritedData('$uiView')),
262253
locals = current && current.locals[name];
263254

264255
if (! locals) {
@@ -286,5 +277,14 @@ function $ViewDirectiveFill ($compile, $controller, $state) {
286277
};
287278
}
288279

280+
/**
281+
* Shared ui-view code for both directives:
282+
* Given attributes and inherited $uiView data, return the view's name
283+
*/
284+
function getUiViewName(attrs, inherited) {
285+
var name = attrs.uiView || attrs.name || '';
286+
return name.indexOf('@') >= 0 ? name : (name + '@' + (inherited ? inherited.state.name : ''));
287+
}
288+
289289
angular.module('ui.router.state').directive('uiView', $ViewDirective);
290290
angular.module('ui.router.state').directive('uiView', $ViewDirectiveFill);

test/stateDirectivesSpec.js

+47
Original file line numberDiff line numberDiff line change
@@ -447,3 +447,50 @@ describe('uiSrefActive', function() {
447447
expect(angular.element(template[0].querySelector('a')).attr('class')).toBe('ng-scope');
448448
}));
449449
});
450+
451+
describe('uiView controllers or onEnter handlers', function() {
452+
var el, template, scope, document, count;
453+
454+
beforeEach(module('ui.router'));
455+
456+
beforeEach(module(function($stateProvider) {
457+
count = 0;
458+
$stateProvider
459+
.state('aside', { url: '/aside', template: '<div class="aside"></div>' })
460+
.state('A', { url: '/A', template: '<div class="A" ui-view="fwd"></div>' })
461+
.state('A.fwd', {
462+
url: '/fwd', views: { 'fwd@A': {
463+
template: '<div class="fwd" ui-view>',
464+
controller: function($state) { if (count++ < 20 && $state.current.name == 'A.fwd') $state.go(".nest"); }
465+
}}
466+
})
467+
.state('A.fwd.nest', { url: '/nest', template: '<div class="nest"></div>' });
468+
}));
469+
470+
beforeEach(inject(function($document) {
471+
document = $document[0];
472+
}));
473+
474+
it('should not go into an infinite loop when controller uses $state.go', inject(function($rootScope, $q, $compile, $state) {
475+
el = angular.element('<div><ui-view></ui-view></div>');
476+
template = $compile(el)($rootScope);
477+
$rootScope.$digest();
478+
479+
$state.transitionTo('aside');
480+
$q.flush();
481+
expect(template[0].querySelector('.aside')).toBeDefined();
482+
expect(template[0].querySelector('.fwd')).toBeNull();
483+
484+
$state.transitionTo('A');
485+
$q.flush();
486+
expect(template[0].querySelector('.A')).not.toBeNull();
487+
expect(template[0].querySelector('.fwd')).toBeNull();
488+
489+
$state.transitionTo('A.fwd');
490+
$q.flush();
491+
expect(template[0].querySelector('.A')).not.toBeNull();
492+
expect(template[0].querySelector('.fwd')).not.toBeNull();
493+
expect(template[0].querySelector('.nest')).not.toBeNull();
494+
expect(count).toBe(1);
495+
}));
496+
});

0 commit comments

Comments
 (0)