Scroll to page top on transition, like a non-SPA website. An alternative scroll behavior for Ember applications.
ember install ember-router-scroll
Like all good ember addons, this behavior was considered for core implementation. Good news, people like the idea. For now, the feature will live under the flag ember-unique-location-history-state
until it's finally released in Ember 2.13. You can follow along for yourself here and read up on the RFC if you'd like as well.
See demo and repo made by Jon Chua.
Notice that the in the full purple page, the user is sent to the middle of the page
Notice that the in the full purple page, the user is sent to the top of the page
Ember expects an application to be rendered with nested views. The default behavior is for the scroll position to be preserved on every transition.
However not all Ember applications use nested views. For these applications, a user would expect to see the top of the page on most transitions.
In addition to scrolling to the top of the page on most transitions, a user would expect the scroll position to be preserved when using the back or forward browser buttons.
Ember-router-scroll makes your single page application feel more like a regular website.
For the purposes of this section, here are some definitions:
previous route
: the route you are leaving
next route
: the route you are going to next
popStateEvent
: the event triggered by clicking the back or forward button in the browser. See more here at mdn.
Ember-router-scroll is a mixin that adds behavior to the willTransition
and didTransition
hooks in the router.
When willTransition
is triggered, the scroll position is stored in a map with the previous route's ID from the HistoryLocation API as the key with the scroll position as the value.
scrollMap[previous_route] = 1234
On didTransition
, it first checks to see if the route transition was triggered by a popStateEvent
. If so, go to the scroll position defined by the scrollMap
. Otherwise, scroll to the top of the page.
With one exception: if the queryParam preserveScrollPosition
is set to true
, it maintains the scroll position of the previous route. See below for further information on this queryParam.
ember install ember-router-scroll
In your app/router.js file, import the mixin:
import RouterScroll from 'ember-router-scroll';
And add RouterScroll as an extension to your Router object:
const Router = Ember.Router.extend(RouterScroll, {}
Edit config/environment.js
and change locationType
.
Also add historySupportMiddleware: true,
to get live-reload working in nested routes. (See Issue #21)
locationType: 'router-scroll',
historySupportMiddleware: true,
This location type inherits from Ember's HistoryLocation
.
In your router and controller tests, add 'service:router-scroll',
it as a dependency in the needs: []
block:
//{your-app}}/tests/unit/routes/{{your-route}}.js
needs:[ 'service:router-scroll' ],
Notice the unwanted scroll to top in this case.
Adding a query parameter fixes this issue.
In certain cases, you might want to have certain routes preserve scroll position when coming from a specific location. For example, inside your application, there is a way to get to a route where the user expects scroll position to be preserved (such as a tab section).
To use this feature:
Add preserveScrollPosition
as a queryParam in the controller for the route that needs to preserve the scroll position.
Example:
import Ember from 'ember';
export default Ember.Controller.extend({
queryParams: [
'preserveScrollPosition',
],
});
Next, in the place where a transition is triggered, pass in preserveScrollPosition=true
. For example
git clone
this repositorynpm install
bower install
ember server
- Visit your app at http://localhost:4200.
npm test
(Runsember try:testall
to test your addon against multiple Ember versions)ember test
ember test --server
ember build
For more information on using ember-cli, visit http://ember-cli.com/.