From 90af4763d8018ab18534dbc0bf9fe8e584deb163 Mon Sep 17 00:00:00 2001 From: Fabian Raetz Date: Sat, 26 Mar 2016 10:35:06 +0100 Subject: [PATCH] fix(angular1_router): delay view update until activate promise gets fullfilled If the $routerOnActivate hook returns a promise, the navigation is commited, once the promise gets fullfilled but the view is updated immediately. This commit delays the view update so that both (view and url) are updated at the same time. Closes #7777 --- modules/angular1_router/src/ng_outlet.ts | 12 ++--- .../test/integration/lifecycle_hook_spec.js | 44 ++++++++++++++++++- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/modules/angular1_router/src/ng_outlet.ts b/modules/angular1_router/src/ng_outlet.ts index f348020287..ea4e723408 100644 --- a/modules/angular1_router/src/ng_outlet.ts +++ b/modules/angular1_router/src/ng_outlet.ts @@ -118,14 +118,16 @@ function ngOutletDirective($animate, $q: ng.IQService, $rootRouter) { newScope.$$router = this.controller.$$router; this.deferredActivation = $q.defer(); - let clone = $transclude(newScope, clone => { + let clone = $transclude(newScope, clone => {}); + + let activateView = () => { $animate.enter(clone, null, this.currentElement || element); this.cleanupLastView(); - }); + this.currentElement = clone; + this.currentScope = newScope; + }; - this.currentElement = clone; - this.currentScope = newScope; - return this.deferredActivation.promise; + return this.deferredActivation.promise.then(activateView, activateView); } } diff --git a/modules/angular1_router/test/integration/lifecycle_hook_spec.js b/modules/angular1_router/test/integration/lifecycle_hook_spec.js index 915740bc14..461103272f 100644 --- a/modules/angular1_router/test/integration/lifecycle_hook_spec.js +++ b/modules/angular1_router/test/integration/lifecycle_hook_spec.js @@ -3,6 +3,7 @@ describe('Navigation lifecycle', function () { var elt, $compile, + $q, $rootScope, $rootRouter, $compileProvider; @@ -14,8 +15,9 @@ describe('Navigation lifecycle', function () { $compileProvider = _$compileProvider_; }); - inject(function (_$compile_, _$rootScope_, _$rootRouter_) { + inject(function (_$compile_, _$q_, _$rootScope_, _$rootRouter_) { $compile = _$compile_; + $q = _$q_; $rootScope = _$rootScope_; $rootRouter = _$rootRouter_; }); @@ -89,6 +91,46 @@ describe('Navigation lifecycle', function () { instructionFor('oneCmp')); }); + describe('activate hook with promise', () => { + var activateDeferred; + beforeEach(() => { + activateDeferred = $q.defer(); + var activate = registerComponent('activateCmp', { + template: 'hi', + $routerOnActivate: function() { + return activateDeferred.promise; + } + }); + + $rootRouter.config([ + { path: '/user/:name', component: 'oneCmp' }, + { path: '/post', component: 'activateCmp' }, + ]); + compile('
'); + + $rootRouter.navigateByUrl('/user/fabian'); + $rootScope.$digest(); + $rootRouter.navigateByUrl('/post'); + $rootScope.$digest(); + }); + + it('should update the view once the promise gets resolved', () => { + expect(elt.text()).toBe('one'); + + activateDeferred.resolve(); + $rootScope.$digest(); + expect(elt.text()).toBe('hi'); + }); + + it('should update the view once the promise gets rejected', () => { + expect(elt.text()).toBe('one'); + + activateDeferred.reject(); + $rootScope.$digest(); + expect(elt.text()).toBe('hi'); + }); + }); + it('should inject $scope into the controller constructor', function () { var injectedScope; registerComponent('userCmp', {