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

Commit d378f55

Browse files
petebacondarwinjeffbcross
authored andcommitted
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
1 parent 9470080 commit d378f55

File tree

2 files changed

+92
-30
lines changed

2 files changed

+92
-30
lines changed

src/ng/directive/ngInclude.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
176176
};
177177

178178
scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
179+
var afterAnimation = function() {
180+
if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
181+
$anchorScroll();
182+
}
183+
};
179184
var thisChangeId = ++changeCounter;
180185

181186
if (src) {
@@ -190,13 +195,8 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
190195
currentElement = clone;
191196

192197
currentElement.html(response);
193-
$animate.enter(currentElement, null, $element);
198+
$animate.enter(currentElement, null, $element, afterAnimation);
194199
$compile(currentElement.contents())(currentScope);
195-
196-
if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
197-
$anchorScroll();
198-
}
199-
200200
currentScope.$emit('$includeContentLoaded');
201201
scope.$eval(onloadExp);
202202
});

test/ng/directive/ngIncludeSpec.js

+86-24
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ describe('ngInclude', function() {
312312
}));
313313

314314

315-
describe('autoscoll', function() {
315+
describe('autoscroll', function() {
316316
var autoScrollSpy;
317317

318318
function spyOnAnchorScroll() {
@@ -328,52 +328,114 @@ describe('ngInclude', function() {
328328
};
329329
}
330330

331-
function changeTplAndValueTo(template, value) {
332-
return function($rootScope, $browser) {
333-
$rootScope.$apply(function() {
334-
$rootScope.tpl = template;
335-
$rootScope.value = value;
336-
});
337-
};
338-
}
339-
340-
beforeEach(module(spyOnAnchorScroll()));
331+
beforeEach(module(spyOnAnchorScroll(), 'mock.animate'));
341332
beforeEach(inject(
342333
putIntoCache('template.html', 'CONTENT'),
343334
putIntoCache('another.html', 'CONTENT')));
344335

345-
346336
it('should call $anchorScroll if autoscroll attribute is present', inject(
347337
compileAndLink('<div><ng:include src="tpl" autoscroll></ng:include></div>'),
348-
changeTplAndValueTo('template.html'), function() {
338+
function($rootScope, $animate, $timeout) {
339+
340+
$rootScope.$apply(function () {
341+
$rootScope.tpl = 'template.html';
342+
});
343+
344+
expect(autoScrollSpy).not.toHaveBeenCalled();
345+
$animate.flushNext('enter');
346+
$timeout.flush();
347+
349348
expect(autoScrollSpy).toHaveBeenCalledOnce();
350349
}));
351350

352351

353-
it('should call $anchorScroll if autoscroll evaluates to true', inject(
354-
compileAndLink('<div><ng:include src="tpl" autoscroll="value"></ng:include></div>'),
355-
changeTplAndValueTo('template.html', true),
356-
changeTplAndValueTo('another.html', 'some-string'),
357-
changeTplAndValueTo('template.html', 100), function() {
352+
it('should call $anchorScroll if autoscroll evaluates to true',
353+
inject(function($rootScope, $compile, $animate, $timeout) {
354+
355+
element = $compile('<div><ng:include src="tpl" autoscroll="value"></ng:include></div>')($rootScope);
356+
357+
$rootScope.$apply(function () {
358+
$rootScope.tpl = 'template.html';
359+
$rootScope.value = true;
360+
});
361+
362+
$animate.flushNext('enter');
363+
$timeout.flush();
364+
365+
$rootScope.$apply(function () {
366+
$rootScope.tpl = 'another.html';
367+
$rootScope.value = 'some-string';
368+
});
369+
370+
$animate.flushNext('leave');
371+
$animate.flushNext('enter');
372+
$timeout.flush();
373+
374+
$rootScope.$apply(function() {
375+
$rootScope.tpl = 'template.html';
376+
$rootScope.value = 100;
377+
});
378+
379+
$animate.flushNext('leave');
380+
$animate.flushNext('enter');
381+
$timeout.flush();
382+
358383
expect(autoScrollSpy).toHaveBeenCalled();
359384
expect(autoScrollSpy.callCount).toBe(3);
360385
}));
361386

362387

363388
it('should not call $anchorScroll if autoscroll attribute is not present', inject(
364389
compileAndLink('<div><ng:include src="tpl"></ng:include></div>'),
365-
changeTplAndValueTo('template.html'), function() {
390+
function($rootScope, $animate, $timeout) {
391+
392+
$rootScope.$apply(function () {
393+
$rootScope.tpl = 'template.html';
394+
});
395+
396+
$animate.flushNext('enter');
397+
$timeout.flush();
366398
expect(autoScrollSpy).not.toHaveBeenCalled();
367399
}));
368400

369401

370-
it('should not call $anchorScroll if autoscroll evaluates to false', inject(
371-
compileAndLink('<div><ng:include src="tpl" autoscroll="value"></ng:include></div>'),
372-
changeTplAndValueTo('template.html', false),
373-
changeTplAndValueTo('template.html', undefined),
374-
changeTplAndValueTo('template.html', null), function() {
402+
it('should not call $anchorScroll if autoscroll evaluates to false',
403+
inject(function($rootScope, $compile, $animate, $timeout) {
404+
405+
element = $compile('<div><ng:include src="tpl" autoscroll="value"></ng:include></div>')($rootScope);
406+
407+
$rootScope.$apply(function () {
408+
$rootScope.tpl = 'template.html';
409+
$rootScope.value = false;
410+
});
411+
412+
$animate.flushNext('enter');
413+
$timeout.flush();
414+
415+
$rootScope.$apply(function () {
416+
$rootScope.tpl = 'template.html';
417+
$rootScope.value = undefined;
418+
});
419+
420+
$rootScope.$apply(function () {
421+
$rootScope.tpl = 'template.html';
422+
$rootScope.value = null;
423+
});
424+
375425
expect(autoScrollSpy).not.toHaveBeenCalled();
376426
}));
427+
428+
it('should only call $anchorScroll after the "enter" animation completes', inject(
429+
compileAndLink('<div><ng:include src="tpl" autoscroll></ng:include></div>'),
430+
function($rootScope, $animate, $timeout) {
431+
expect(autoScrollSpy).not.toHaveBeenCalled();
432+
433+
$rootScope.$apply("tpl = 'template.html'");
434+
$animate.flushNext('enter');
435+
$timeout.flush();
436+
437+
expect(autoScrollSpy).toHaveBeenCalledOnce();
438+
}));
377439
});
378440
});
379441

0 commit comments

Comments
 (0)