1

Im building a phonegap app and have implemented angularjs in it. The app uses my jquery plugin for page transitions, so each page is loaded using ajax. Each HTML page has its own controller in a separate JS file. So the logic is basically:

  1. Load all JS files (controllers) at the index page.
  2. Run my page transition plugin and change page. When done do a callback and run this code to trigger the angularjs controller:

    $(document).on('pageready', function(e, input) {
    
        $(input.page).attr('ng-init','init('+JSON.stringify(input.params)+')');
        angular.bootstrap($(input.page), []);
    
    });
    
  3. The code above will trigger the controller for the newly loaded page

This works great. My problem is that I have 1 page that has scrollable content. I cache this list and when the app user visit the page a second time I want to scroll to the position the user was on last in the list. I solved this using:

$scope.$watch('$last',function(){
    $scope.$apply();
    $("#mylist").scrollTop($scope.input.scroll);
 });

but this throws an error: ERROR: Error: [$rootScope:inprog]

I've tried a lot of different things to get rid of this error but the above code is the only thing that I have manged to use to set the scroll position:

  1. I tried not using apply, but then the scroll is never done.
  2. I've tried using directives, but due to my setup these are not called, only the controller is triggered on page change
  3. I tried angular.element(document).ready(function () { --- No effect
  4. I tried $scope.$on('$viewContentLoaded', function() { --- No effect
  5. I tried $scope.$watch('$viewContentLoaded', function() { --- No effect

I probably tried more but without luck. Any ideas?

Thanks.

user727507
  • 275
  • 1
  • 2
  • 11

1 Answers1

0

The reason you're getting the error when calling $scope.$apply() is because it's inside a $watch, and a digest cycle is already in progress (calling $apply() triggers a digest cycle). You should only call $scope.$apply() when something is happening outside of Angular, like an event that Angular doesn't know about.

I think the problem is because your watch fires before Angular is actually done rendering the list. You might be able to solve it with an (ugly) setTimeout(), like this:

$scope.$watch('$last', function(){
  setTimeout(function() {
    $("#mylist").scrollTop($scope.input.scroll);
  }, 0);
});

And change the timeout to higher if that doesn't solve it. Not sure why you're doing this inside a watch for $last though, do you have a reason for doing that? The $last variable is only set on the ng-repeat scope, which you probably don't have access to.

It's probably a better idea to do it when $viewContentLoaded fires, like this:

$scope.$on('$viewContentLoaded', function(){
  setTimeout(function() {
    $("#mylist").scrollTop($scope.input.scroll);
  }, 0);
});
Anders Ekdahl
  • 22,685
  • 4
  • 70
  • 59
  • $scope.$on('$viewContentLoaded' is never triggered. $scope.$watch('$viewContentLoaded' is triggered but adding the timeout in that function seems to cause some sort of error - the page turns blank when function is triggered. – user727507 Mar 14 '14 at 08:53
  • 1
    I want to trigger scroll to when ng-reapet is done. Any other solutions? – user727507 Mar 14 '14 at 08:54
  • Maybe this post can help you: http://stackoverflow.com/questions/13471129/angularjs-ng-repeat-finish-event. It's an example of how to do something when `ng-repeat` is done. So in that example, you'd replace `window.alert("im the last!");` with your code that sets the scrollTop. – Anders Ekdahl Mar 14 '14 at 09:02
  • thanks, I cant get that to work. They use a directive and I need to do it in the controller. – user727507 Mar 14 '14 at 09:44
  • Sorry, it worked. 0 worked but I increased the value directley, which didnt work. Thanks – user727507 Mar 14 '14 at 15:21