From 732ca80f6d5e1e924076d6c25bad63cf97f5fb0d Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Sat, 2 Nov 2013 09:22:26 +0000 Subject: [PATCH] fix(ngInclude): only run anchorScroll after animation is done We need to wait until animations have added the content to the document before trying to `autoscroll` to anchors that may have been inserted. Fixes #4723 --- src/ng/directive/ngInclude.js | 14 ++++++++------ test/ng/directive/ngIncludeSpec.js | 26 +++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/ng/directive/ngInclude.js b/src/ng/directive/ngInclude.js index 13b472341530..86ee3cf89d3b 100644 --- a/src/ng/directive/ngInclude.js +++ b/src/ng/directive/ngInclude.js @@ -178,6 +178,13 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile' }; scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) { + var afterAnimation = function() { + + if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) { + $anchorScroll(); + } + + }; var thisChangeId = ++changeCounter; if (src) { @@ -192,13 +199,8 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile' currentElement = clone; currentElement.html(response); - $animate.enter(currentElement, null, $element); + $animate.enter(currentElement, null, $element, afterAnimation); $compile(currentElement.contents())(currentScope); - - if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) { - $anchorScroll(); - } - currentScope.$emit('$includeContentLoaded'); scope.$eval(onloadExp); }); diff --git a/test/ng/directive/ngIncludeSpec.js b/test/ng/directive/ngIncludeSpec.js index b8b0c16bdd1d..4427bcce55f4 100644 --- a/test/ng/directive/ngIncludeSpec.js +++ b/test/ng/directive/ngIncludeSpec.js @@ -322,6 +322,18 @@ describe('ngInclude', function() { }; } + function spyOnAnimateEnter() { + return function($animate) { + spyOn($animate, 'enter').andCallThrough(); + }; + } + + function runEnterAnimation($animate) { + if ($animate.enter.mostRecentCall) { + $animate.enter.mostRecentCall.args[3](); + } + } + function compileAndLink(tpl) { return function($compile, $rootScope) { element = $compile(tpl)($rootScope); @@ -329,15 +341,17 @@ describe('ngInclude', function() { } function changeTplAndValueTo(template, value) { - return function($rootScope, $browser) { + return function($rootScope, $browser, $animate) { $rootScope.$apply(function() { $rootScope.tpl = template; $rootScope.value = value; }); + runEnterAnimation($animate); }; } beforeEach(module(spyOnAnchorScroll())); + beforeEach(inject(spyOnAnimateEnter())); beforeEach(inject( putIntoCache('template.html', 'CONTENT'), putIntoCache('another.html', 'CONTENT'))); @@ -374,6 +388,16 @@ describe('ngInclude', function() { changeTplAndValueTo('template.html', null), function() { expect(autoScrollSpy).not.toHaveBeenCalled(); })); + + it('should only call $anchorScroll after the "enter" animation completes', inject( + compileAndLink('
'), + function($rootScope, $animate) { + $rootScope.$apply("tpl = 'template.html'"); + expect($animate.enter).toHaveBeenCalledOnce(); + expect(autoScrollSpy).not.toHaveBeenCalled(); + runEnterAnimation($animate); + expect(autoScrollSpy).toHaveBeenCalledOnce(); + })); }); });