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
This commit is contained in:
Fabian Raetz 2016-03-26 10:35:06 +01:00 committed by Misko Hevery
parent 390046d7b3
commit 90af4763d8
2 changed files with 50 additions and 6 deletions

View File

@ -118,14 +118,16 @@ function ngOutletDirective($animate, $q: ng.IQService, $rootRouter) {
newScope.$$router = this.controller.$$router; newScope.$$router = this.controller.$$router;
this.deferredActivation = $q.defer(); this.deferredActivation = $q.defer();
let clone = $transclude(newScope, clone => { let clone = $transclude(newScope, clone => {});
let activateView = () => {
$animate.enter(clone, null, this.currentElement || element); $animate.enter(clone, null, this.currentElement || element);
this.cleanupLastView(); this.cleanupLastView();
}); this.currentElement = clone;
this.currentScope = newScope;
};
this.currentElement = clone; return this.deferredActivation.promise.then(activateView, activateView);
this.currentScope = newScope;
return this.deferredActivation.promise;
} }
} }

View File

@ -3,6 +3,7 @@
describe('Navigation lifecycle', function () { describe('Navigation lifecycle', function () {
var elt, var elt,
$compile, $compile,
$q,
$rootScope, $rootScope,
$rootRouter, $rootRouter,
$compileProvider; $compileProvider;
@ -14,8 +15,9 @@ describe('Navigation lifecycle', function () {
$compileProvider = _$compileProvider_; $compileProvider = _$compileProvider_;
}); });
inject(function (_$compile_, _$rootScope_, _$rootRouter_) { inject(function (_$compile_, _$q_, _$rootScope_, _$rootRouter_) {
$compile = _$compile_; $compile = _$compile_;
$q = _$q_;
$rootScope = _$rootScope_; $rootScope = _$rootScope_;
$rootRouter = _$rootRouter_; $rootRouter = _$rootRouter_;
}); });
@ -89,6 +91,46 @@ describe('Navigation lifecycle', function () {
instructionFor('oneCmp')); 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('<div ng-outlet></div>');
$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 () { it('should inject $scope into the controller constructor', function () {
var injectedScope; var injectedScope;
registerComponent('userCmp', { registerComponent('userCmp', {