Skip to content

Commit 69b47be

Browse files
committed
feat($anchorScroll): add support for scrolling independently of $location.hash()
Add an optional argument to `$anchorScroll()` to enable scrolling to an anchor element different than that related to the current value of `$location.hash()`. If the argument is omitted, the value of `$location.hash()` will be used instead. Closes angular#4568
1 parent bf6a79c commit 69b47be

File tree

2 files changed

+113
-38
lines changed

2 files changed

+113
-38
lines changed

src/ng/anchorScroll.js

+10-5
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ function $AnchorScrollProvider() {
3838
* @requires $rootScope
3939
*
4040
* @description
41-
* When called, it checks the current value of {@link ng.$location#hash $location.hash()} and
42-
* scrolls to the related element, according to the rules specified in the
43-
* [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
41+
* When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
42+
* current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
43+
* in the
44+
* [HTML5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
4445
*
4546
* It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
4647
* match any anchor whenever it changes. This can be disabled by calling
@@ -49,6 +50,9 @@ function $AnchorScrollProvider() {
4950
* Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
5051
* vertical scroll-offset (either fixed or dynamic).
5152
*
53+
* @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
54+
* {@link ng.$location#hash $location.hash()} will be used.
55+
*
5256
* @property {(number|function|jqLite)} yOffset
5357
* If set, specifies a vertical scroll-offset. This is often useful when there are fixed
5458
* positioned elements at the top of the page, such as navbars, headers etc.
@@ -232,8 +236,9 @@ function $AnchorScrollProvider() {
232236
}
233237
}
234238

235-
function scroll() {
236-
var hash = $location.hash(), elm;
239+
function scroll(hash) {
240+
hash = (arguments.length && isString(hash)) ? hash : $location.hash();
241+
var elm;
237242

238243
// empty hash, scroll to the top of the page
239244
if (!hash) scrollTo(null);

test/ng/anchorScrollSpec.js

+103-33
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ describe('$anchorScroll', function() {
2323
};
2424
}
2525

26-
2726
function addElements() {
2827
var elements = sliceArgs(arguments);
2928

@@ -49,9 +48,10 @@ describe('$anchorScroll', function() {
4948
};
5049
}
5150

52-
function callAnchorScroll() {
51+
function callAnchorScroll(hash) {
52+
var args = arguments;
5353
return function($anchorScroll) {
54-
$anchorScroll();
54+
$anchorScroll.apply(null, args);
5555
};
5656
}
5757

@@ -141,50 +141,120 @@ describe('$anchorScroll', function() {
141141
beforeEach(createMockWindow());
142142

143143

144-
it('should scroll to top of the window if empty hash', inject(
145-
changeHashAndScroll(''),
146-
expectScrollingToTop));
144+
describe('and implicitly using `$location.hash()`', function() {
145+
146+
it('should scroll to top of the window if empty hash', inject(
147+
changeHashAndScroll(''),
148+
expectScrollingToTop));
149+
150+
151+
it('should not scroll if hash does not match any element', inject(
152+
addElements('id=one', 'id=two'),
153+
changeHashAndScroll('non-existing'),
154+
expectNoScrolling()));
155+
156+
157+
it('should scroll to anchor element with name', inject(
158+
addElements('a name=abc'),
159+
changeHashAndScroll('abc'),
160+
expectScrollingTo('a name=abc')));
161+
162+
163+
it('should not scroll to other than anchor element with name', inject(
164+
addElements('input name=xxl', 'select name=xxl', 'form name=xxl'),
165+
changeHashAndScroll('xxl'),
166+
expectNoScrolling()));
167+
168+
169+
it('should scroll to anchor even if other element with given name exist', inject(
170+
addElements('input name=some', 'a name=some'),
171+
changeHashAndScroll('some'),
172+
expectScrollingTo('a name=some')));
173+
174+
175+
it('should scroll to element with id with precedence over name', inject(
176+
addElements('name=abc', 'id=abc'),
177+
changeHashAndScroll('abc'),
178+
expectScrollingTo('id=abc')));
147179

148180

149-
it('should not scroll if hash does not match any element', inject(
150-
addElements('id=one', 'id=two'),
151-
changeHashAndScroll('non-existing'),
152-
expectNoScrolling()));
181+
it('should scroll to top if hash == "top" and no matching element', inject(
182+
changeHashAndScroll('top'),
183+
expectScrollingToTop));
153184

154185

155-
it('should scroll to anchor element with name', inject(
156-
addElements('a name=abc'),
157-
changeHashAndScroll('abc'),
158-
expectScrollingTo('a name=abc')));
186+
it('should scroll to element with id "top" if present', inject(
187+
addElements('id=top'),
188+
changeHashAndScroll('top'),
189+
expectScrollingTo('id=top')));
190+
});
191+
192+
193+
describe('and specifying a hash', function() {
194+
195+
it('should ignore the `hash` argument if not a string', inject(
196+
spyOnJQLiteDocumentLoaded(),
197+
addElements('id=one', 'id=two'),
198+
changeHashTo('one'), // won't scroll since `jqLiteDocumentLoaded()` is spied upon
199+
callAnchorScroll({}),
200+
expectScrollingTo('id=one'),
201+
unspyOnJQLiteDocumentLoaded()));
202+
203+
204+
it('should ignore `$location.hash()` if `hash` is passed as argument', inject(
205+
spyOnJQLiteDocumentLoaded(),
206+
addElements('id=one', 'id=two'),
207+
changeHashTo('one'), // won't scroll since `jqLiteDocumentLoaded()` is spied upon
208+
callAnchorScroll('two'),
209+
expectScrollingTo('id=two'),
210+
unspyOnJQLiteDocumentLoaded()));
211+
159212

213+
it('should scroll to top of the window if empty hash', inject(
214+
callAnchorScroll(''),
215+
expectScrollingToTop));
160216

161-
it('should not scroll to other than anchor element with name', inject(
162-
addElements('input name=xxl', 'select name=xxl', 'form name=xxl'),
163-
changeHashAndScroll('xxl'),
164-
expectNoScrolling()));
165217

218+
it('should not scroll if hash does not match any element', inject(
219+
addElements('id=one', 'id=two'),
220+
callAnchorScroll('non-existing'),
221+
expectNoScrolling()));
166222

167-
it('should scroll to anchor even if other element with given name exist', inject(
168-
addElements('input name=some', 'a name=some'),
169-
changeHashAndScroll('some'),
170-
expectScrollingTo('a name=some')));
171223

224+
it('should scroll to anchor element with name', inject(
225+
addElements('a name=abc'),
226+
callAnchorScroll('abc'),
227+
expectScrollingTo('a name=abc')));
172228

173-
it('should scroll to element with id with precedence over name', inject(
174-
addElements('name=abc', 'id=abc'),
175-
changeHashAndScroll('abc'),
176-
expectScrollingTo('id=abc')));
177229

230+
it('should not scroll to other than anchor element with name', inject(
231+
addElements('input name=xxl', 'select name=xxl', 'form name=xxl'),
232+
callAnchorScroll('xxl'),
233+
expectNoScrolling()));
178234

179-
it('should scroll to top if hash == "top" and no matching element', inject(
180-
changeHashAndScroll('top'),
181-
expectScrollingToTop));
182235

236+
it('should scroll to anchor even if other element with given name exist', inject(
237+
addElements('input name=some', 'a name=some'),
238+
callAnchorScroll('some'),
239+
expectScrollingTo('a name=some')));
183240

184-
it('should scroll to element with id "top" if present', inject(
185-
addElements('id=top'),
186-
changeHashAndScroll('top'),
187-
expectScrollingTo('id=top')));
241+
242+
it('should scroll to element with id with precedence over name', inject(
243+
addElements('name=abc', 'id=abc'),
244+
callAnchorScroll('abc'),
245+
expectScrollingTo('id=abc')));
246+
247+
248+
it('should scroll to top if hash == "top" and no matching element', inject(
249+
callAnchorScroll('top'),
250+
expectScrollingToTop));
251+
252+
253+
it('should scroll to element with id "top" if present', inject(
254+
addElements('id=top'),
255+
callAnchorScroll('top'),
256+
expectScrollingTo('id=top')));
257+
});
188258
});
189259

190260

0 commit comments

Comments
 (0)