Angular ui-router scroll up, not in ui-view

I just upgraded to ui-router 0.2.8 from 0.2.0 , and I noticed that when the state changes, the scroll position will move to the beginning of te child ui-view , which is the subject of the new state.

This is good, but I have two problems:

1) I have 30px padding between the top of the page and the ui-view , and I would like it to scroll to the top of the page, leaving a space. At the moment, he goes exactly to the top of the ui-view , which looks ugly. To achieve this, I think I need to know how to make it scroll at the top of the div where the ui-view is located (and not in the viewport browser), or I need to figure out how to override $uiViewScroll to scroll to ui-view minus 30px.

I tried $uiViewScrollProvider.useAnchorScroll(); but if I do, it doesn't scroll at all. I also tried <ui-view autoscroll="false">; , which also completely stops scrolling.

2) At the moment, it does not actually scroll, it just jumps. Is scrolling supposed to, or is it up to the developer to do this with CSS transitions?

Any help would be really appreciated :)

+64
javascript angularjs angular-ui-router angular-ui
Mar 10 '14 at 1:20
source share
10 answers

Another approach is to decorate the default $uiViewScroll , effectively overriding the default behavior.

 app.config(function ($provide) { $provide.decorator('$uiViewScroll', function ($delegate) { return function (uiViewElement) { // var top = uiViewElement.getBoundingClientRect().top; // window.scrollTo(0, (top - 30)); // Or some other custom behaviour... }; }); }); 

And as Hubrus said, for any <ui-view> you don’t want this to be an expression, just add autoscroll="false" . I didn’t look very well at the actual implementation of the scroll, I just thought that as an alternative I would mention the style of the decorator (this is a lot of fun). I'm sure you can work out the exact scroll behavior.

+51
Mar 20 '14 at 11:58
source share

when ever the path changes the router, it sends an event: $ stateChangeSuccess, i.e. The url has changed, so just listen to it and use jquery to scroll to the top of the page

 $rootScope.$on('$stateChangeSuccess',function(){ $("html, body").animate({ scrollTop: 0 }, 200); }) 

put the above code inside

 yourAppName.run(function(){ //the above code here }) 
+41
Mar 15 '14 at 5:55 a.m.
source share

So I had the same problem. I have a fixed top navigation bar. If I put autoscroll = "true" in the u-view, it would scroll up to minus the height of the scrollbar height.

So, I got rid of the style that added a pad to the body for the top navigation bar

 // fixed navigation at top //body { padding-top: 100px; } 

And applied it to ui-view

 [ui-view=main] { padding-top: 100px; } 

Now autoscroll = "true" works as expected.

+11
Aug 28 '14 at 14:21
source share

1) I think the easiest way to place autoscroll="false" on ui-view and manipulate scrolling in the $viewContentLoaded event.

2) This is the default browser behavior anchored

+7
Mar 14 '14 at 15:02
source share

Since $stateChangeSuccess seems to no longer be available in the current AngularJS (like 1.2.x), I changed the Rishul Mattas Example to the following, which works great for me:

 app.run(function ($rootScope) { $rootScope.$on('$viewContentLoaded',function(){ jQuery('html, body').animate({ scrollTop: 0 }, 200); }); }); 
+5
Aug 08 '14 at 2:35
source share

Top place

 <div id="top">..... 

Code to scroll:

 $rootScope.$on('$stateChangeStart', function() { $anchorScroll('top'); }); 
+2
Mar 28 '16 at 10:40
source share

If you combine Angular + Material Design, you also need to scroll up:

 app.run(function ($rootScope) { $rootScope.$on('$viewContentLoaded', function () { $("md-content").animate({ scrollTop: 0 }, "fast"); /* <------- Notice this line */ jQuery('html, body').animate({ scrollTop: 0 }, 200); }); }); 
+1
Dec 08 '14 at 6:03
source share

I think we do not need to scroll up if the navigation state is a child, so I wrote this:

 $rootScope.$on('$stateChangeSuccess',function(_, _, _, os){ if(!$state.includes(os) || $state.is(os)) $("html, body").animate({ scrollTop: 0 }, 200); }); 
+1
Dec 14 '14 at 2:49
source share

In most cases, this is not enough to scroll to the top of the page. It is always recommended that you refer to anchor links and scroll to a specific place in the loaded content, determined by the location hash.

Here is the code that I use to implement this strategy:

 module.run(function ( $rootScope, $timeout, $location, $uiViewScroll ) { // Scrolling when screen changed. $rootScope.$on('$viewContentLoaded', function () { $timeout(performAutoScroll, 0); }); function performAutoScroll () { var hash = $location.hash(); var element = findDomElement('#' + hash) || findDomElement('a[name="' + hash + '"]') || angular.element(window.document.body) ; $uiViewScroll(element); } }); 

$viewContentLoaded - An event generated by Angular when content is loaded inside a ui-view element. In fact, we need to delay the execution of our code in order to move it to the next digest cycle. Thus, the contents of the view element will actually be placed in the DOM tree, so we can request it. $timeout with a zero-delay trick is used for this purpose.

$uiViewScroll service provided by the UI Router is used for actual scrolling. We can pass the jQuery / jqLite element to it, and it will scroll to the top of it.

We get a personal hash from the $location service and use it to find the correct item inside the DOM tree. This can be either an element with an id attribute or a link with a name attribute. In case we cannot find the element to scroll, we return to the body element (i.e., scroll up the page).

And findDomElement is just syntactic sugar. It is defined as follows:

 /** * @param {string} selector * @returns {jQuery|null} */ function findDomElement (selector) { var result = $(selector); return (result.length > 0 ? result : null); } 

I hope this approach makes sense and will be useful to someone out there. Hurrah!

0
Jul 02 '15 at 16:35
source share

If you want to do this with a legend, you can put this in the controller view as follows:

 .state('exampleState', { url: '/exampleURL', controller: 'ExampleCtrl as examplectrl', onEnter: function($rootScope) { $rootScope.$on('$viewContentLoaded',function(){ jQuery('html, body').animate({ scrollTop: 0 }, 200); }); } }). 

or, possibly, this may cause your state.js file cleaner to put the above into the controller for this view:

 function ExampleCtrl ($scope, $rootScope) { $rootScope.$on('$viewContentLoaded',function(){ jQuery('html, body').animate({ scrollTop: 0 }, 200); }); } 

Hope this helps someone, please let me know if I missed something. I used the latter and did a great job for me.

0
Mar 28 '16 at 21:46
source share



All Articles