Skip to content

Commit

Permalink
Router scroll service (#195)
Browse files Browse the repository at this point in the history
  • Loading branch information
lougreenwood authored and snewcomer committed Jun 10, 2019
1 parent bddb1cc commit f1a3b3e
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 1 deletion.
45 changes: 44 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ preserving scroll position is expected. Or you want a particular route to start
behavior but then preserve scroll position when query params change in response to user interaction. Using a controller
property also allows the use of preserveScrollPosition without adding this to the query params.


**1.** Add query param to controller

Add `preserveScrollPosition` as a controller property for the route that needs to preserve the scroll position.
Expand Down Expand Up @@ -226,6 +225,50 @@ export default Route.extend({
```


### preserveScrollPosition via service

You may need to programatically control `preserveScrollPosition` directly from a component. This can be achieved by toggling the `preserveScrollPosition` property on the `routerScroll` service.

One common use case for this is when using query-param-based pagination on a page where `preserveScrollPosition` is expected to be false.

For example, if a route should always scroll to top when loaded, `preserveScrollPosition` would be false. However, a user may then scroll down the page and paginate through some results (where each page is a query param). But because `preserveScrollPosition` is false, the page will scroll back to top on each of these paginations.

This can be fixed by temporarily setting `preserveScrollPosition` to true on the service in the pagination transition action and then disabling `preserveScrollPosition` after the transition occurs.

Note: if `preserveScrollPosition` is set to true on the service, it will override any values set on the current route's controller - whether query param or controller property.


**1.** Manage preserveScrollPosition via service

When you need to modify `preserveScrollPosition` on the service for a specific transition, you should always reset the value after the transition occurs, otherwise all future transitions will use the same `preserveScrollPosition` value.

Example:

```javascript
import Component from '@ember/component';
import { inject as service } from '@ember/service';

export default Component.extend({
routerScroll: service(),
router: service(),

actions: {
async goToPaginationPage(pageNumber) {
this.set('routerScroll.preserveScrollPosition', true);
await this.router.transitionTo(
this.router.currentRouteName,
{
queryParams: { page: pageNumber }
}
);

// Reset `preserveScrollPosition` after transition so future transitions behave as expected
this.set('routerScroll.preserveScrollPosition', false);
}
}
});
```

## Running Tests

* `npm test` (Runs `ember try:testall` to test your addon against multiple Ember versions)
Expand Down
5 changes: 5 additions & 0 deletions addon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ let RouterScrollMixin = Mixin.create({
preserveScrollPosition = transition.some((t) => get(t, 'handler.controller.preserveScrollPosition'));
}

// If `preserveScrollPosition` was not set on the controller, attempt fallback to `preserveScrollPosition` which was set on the router service.
if(!preserveScrollPosition) {
preserveScrollPosition = get(this, 'service.preserveScrollPosition')
}

if (!preserveScrollPosition) {
const scrollElement = get(this, 'service.scrollElement');
const targetElement = get(this, 'service.targetElement');
Expand Down
1 change: 1 addition & 0 deletions addon/services/router-scroll.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const RouterScroll = Service.extend({
targetElement: null,
delayScrollTop: false,
isFirstLoad: true,
preserveScrollPosition: false,

init(...args) {
this._super(...args);
Expand Down
27 changes: 27 additions & 0 deletions tests/unit/mixins/router-scroll-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,33 @@ module('mixin:router-scroll', function(hooks) {
});
});

test('Update Scroll Position: Can preserve position using routerService', function(assert) {
assert.expect(0);
const done = assert.async();

window.scrollTo = () => assert.ok(false, 'Scroll To should not be called');

const RouterScrollObject = EmberObject.extend(Evented, RouterScroll);
subject = RouterScrollObject.create({
isFastBoot: false,
service: {
position: null,
scrollElement: 'window',
}
});

run(() => {
subject.service.preserveScrollPosition = true;

if(gte('3.6.0-beta.1')) {
subject.trigger('routeDidChange', getTransitionsMock('Hello/World', false));
} else {
subject.didTransition(getTransitionsMock('Hello/World', false));
}
done();
});
});

test('Update Scroll Position: URL is an anchor', function(assert) {
assert.expect(1);
const done = assert.async();
Expand Down

0 comments on commit f1a3b3e

Please sign in to comment.