Skip to content

Commit

Permalink
fix(ngInclude): only run anchorScroll after animation is done
Browse files Browse the repository at this point in the history
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 angular#4723
  • Loading branch information
petebacondarwin authored and jeffbcross committed Nov 6, 2013
1 parent 117de8e commit 3479097
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 30 deletions.
12 changes: 6 additions & 6 deletions src/ng/directive/ngInclude.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ 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) {
Expand All @@ -192,13 +197,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);
});
Expand Down
110 changes: 86 additions & 24 deletions test/ng/directive/ngIncludeSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ describe('ngInclude', function() {
}));


describe('autoscoll', function() {
describe('autoscroll', function() {
var autoScrollSpy;

function spyOnAnchorScroll() {
Expand All @@ -328,52 +328,114 @@ describe('ngInclude', function() {
};
}

function changeTplAndValueTo(template, value) {
return function($rootScope, $browser) {
$rootScope.$apply(function() {
$rootScope.tpl = template;
$rootScope.value = value;
});
};
}

beforeEach(module(spyOnAnchorScroll()));
beforeEach(module(spyOnAnchorScroll(), 'mock.animate'));
beforeEach(inject(
putIntoCache('template.html', 'CONTENT'),
putIntoCache('another.html', 'CONTENT')));


it('should call $anchorScroll if autoscroll attribute is present', inject(
compileAndLink('<div><ng:include src="tpl" autoscroll></ng:include></div>'),
changeTplAndValueTo('template.html'), function() {
function($rootScope, $animate, $timeout) {

$rootScope.$apply(function () {
$rootScope.tpl = 'template.html';
});

expect(autoScrollSpy).not.toHaveBeenCalled();
$animate.flushNext('enter');
$timeout.flush();

expect(autoScrollSpy).toHaveBeenCalledOnce();
}));


it('should call $anchorScroll if autoscroll evaluates to true', inject(
compileAndLink('<div><ng:include src="tpl" autoscroll="value"></ng:include></div>'),
changeTplAndValueTo('template.html', true),
changeTplAndValueTo('another.html', 'some-string'),
changeTplAndValueTo('template.html', 100), function() {
it('should call $anchorScroll if autoscroll evaluates to true',
inject(function($rootScope, $compile, $animate, $timeout) {

element = $compile('<div><ng:include src="tpl" autoscroll="value"></ng:include></div>')($rootScope);

$rootScope.$apply(function () {
$rootScope.tpl = 'template.html';
$rootScope.value = true;
});

$animate.flushNext('enter');
$timeout.flush();

$rootScope.$apply(function () {
$rootScope.tpl = 'another.html';
$rootScope.value = 'some-string';
});

$animate.flushNext('leave');
$animate.flushNext('enter');
$timeout.flush();

$rootScope.$apply(function() {
$rootScope.tpl = 'template.html';
$rootScope.value = 100;
});

$animate.flushNext('leave');
$animate.flushNext('enter');
$timeout.flush();

expect(autoScrollSpy).toHaveBeenCalled();
expect(autoScrollSpy.callCount).toBe(3);
}));


it('should not call $anchorScroll if autoscroll attribute is not present', inject(
compileAndLink('<div><ng:include src="tpl"></ng:include></div>'),
changeTplAndValueTo('template.html'), function() {
function($rootScope, $animate, $timeout) {

$rootScope.$apply(function () {
$rootScope.tpl = 'template.html';
});

$animate.flushNext('enter');
$timeout.flush();
expect(autoScrollSpy).not.toHaveBeenCalled();
}));


it('should not call $anchorScroll if autoscroll evaluates to false', inject(
compileAndLink('<div><ng:include src="tpl" autoscroll="value"></ng:include></div>'),
changeTplAndValueTo('template.html', false),
changeTplAndValueTo('template.html', undefined),
changeTplAndValueTo('template.html', null), function() {
it('should not call $anchorScroll if autoscroll evaluates to false',
inject(function($rootScope, $compile, $animate, $timeout) {

element = $compile('<div><ng:include src="tpl" autoscroll="value"></ng:include></div>')($rootScope);

$rootScope.$apply(function () {
$rootScope.tpl = 'template.html';
$rootScope.value = false;
});

$animate.flushNext('enter');
$timeout.flush();

$rootScope.$apply(function () {
$rootScope.tpl = 'template.html';
$rootScope.value = undefined;
});

$rootScope.$apply(function () {
$rootScope.tpl = 'template.html';
$rootScope.value = null;
});

expect(autoScrollSpy).not.toHaveBeenCalled();
}));

it('should only call $anchorScroll after the "enter" animation completes', inject(
compileAndLink('<div><ng:include src="tpl" autoscroll></ng:include></div>'),
function($rootScope, $animate, $timeout) {
expect(autoScrollSpy).not.toHaveBeenCalled();

$rootScope.$apply("tpl = 'template.html'");
$animate.flushNext('enter');
$timeout.flush();

expect(autoScrollSpy).toHaveBeenCalledOnce();
}));
});
});

Expand Down

0 comments on commit 3479097

Please sign in to comment.