JacobF
JacobF

Reputation: 2485

Angular: Scroll to top on click with jquery animate

I want users to smoothly scroll to the top of the page when they click a certain button. I use jQuery's .animate for this. However, whatever I try, Angular warns me that I cannot access DOM elements outside the scope.

This is what I tried:

Template:

<button ng-click="action()">

Controller:

$('html, body').animate({ scrollTop: 0 }, 'slow')

This works but Angular gives the error.

Anybody ideas how to do this the right way?

Upvotes: 2

Views: 6120

Answers (2)

Ali Habibzadeh
Ali Habibzadeh

Reputation: 11548

On your controller simply continue with having only information about the action and not the scroll. as the scroll is an enhancement:

$scope.buttonAction = function () {
    console.log('button action');
} 

In your view use the button normally but now define a directive for it to add additional scroll behaviour:

<button scrollup ng-click="buttonAction()">Click me</button>

and finally your scrolling stuff should be in that scrollup directive:

app.directive('scrollup', function ($document) {
        return {
            restrict: 'A',
            link: function (scope, elm, attrs) {
                elm.bind("click", function () {

                    // Maybe abstract this out in an animation service:
                    // Ofcourse you can replace all this with the jQ 
                    // syntax you have above if you are using jQ
                    function scrollToTop(element, to, duration) {
                        if (duration < 0) return;
                        var difference = to - element.scrollTop;
                        var perTick = difference / duration * 10;

                        setTimeout(function () {
                            element.scrollTop = element.scrollTop + perTick;
                            scrollToTop(element, to, duration - 10);
                        }, 10);
                    }

                    // then just add dependency and call it
                    scrollToTop($document[0].body, 0, 400);
                });
            }
        };
});

Now you will be able to add whatever action you need in your controllers but also have the jumping upo behaviour by adding the directive.

Upvotes: 4

Idkt
Idkt

Reputation: 2996

Why not scroll to the top of the element the scope is working on? If you have something like

<div ng-controller="SomeCtrl">
    …
</div>

And in the controller:

app.controller('SomeCtrl', ['$scope', '$element', function ($scope, $element) {
    $($element).animate(…);
}]);

Upvotes: 0

Related Questions