Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

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 #4723
  • Loading branch information
petebacondarwin authored and jeffbcross committed Nov 6, 2013
1 parent 9470080 commit d378f55
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 @@ -176,6 +176,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 @@ -190,13 +195,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 d378f55

Please sign in to comment.