Reputation: 42480
In my Angular app the following sequence of events needs to happen:
Currently, the scrolling does not work because this is all happening within the same digest. This means that the new state of the ng-show bound variable has not had a chance to update the DOM. Therefore, we attempt to scroll to an element that, as far as the DOM is concerned, is not yet visible.
This is mitigated by wrapping the scroll call with a $timeout, which forces all digest(s) to complete before attempting to scroll. While this works, it feels like a hack, and I want to know if there is a better way of doing this.
Here is a fiddle that demonstrates the problem:
(Note that this code is a simplified version of my real code just to demonstrate the problem, and I realize it does not follow best practices. Rest assured that my real code does not perform direct DOM manipulation in the controller.)
View:
<div ng-app="app" ng-controller="MyCtrl" id="container">
<button ng-click="scroll()">Unhide element and scroll</button> (will not work until $timeout call is uncommented)
<div style="height:1000px; background-color: #ddddd0">
</div>
<div id="target" ng-show="isVisible">section to scroll to</div>
</div>
JS:
angular.module("app", [])
.controller('MyCtrl',
function MyCtrl($scope, $timeout) {
$scope.isVisible = false;
$scope.scroll = function() {
$scope.isVisible = true;
// uncommenting the $timeout fixes it, but feels like a hack
//$timeout(function() {
$('body').animate({
scrollTop: $("#target").offset().top
}, 500);
//});
};
}
);
Upvotes: 2
Views: 1235
Reputation: 2977
Using $timeout is not such a big issue, because the code you are running is not an angular code, and you need to communicate to angular in some way that it needs to refresh the view.
Upvotes: 6