2

I'm writing my first AngularJS application. The landing page has two links #/view1 and #/view2. Every link will call individual controller to render <div ng-view></div> individually.

The view1Ctrl will fetch data from server periodically. I can see ajax call in console every X seconds. Now I click #/view2, the app should use view2Ctrl. I expect view1Ctrl should no longer fetch data from the server. But actually it does.

.controller('View1Ctrl', function($scope, $http) {
  $scope.update = function() {
    $http.get('/api/foo')
      .success(function(data) { /* got new data */ })
      .error(function(data) { /* error occurred */ })
      .finally(function() {
        setTimeout($scope.update, 1000);
      });
  }
  $scope.update();
});

I've two questions:

  1. Is a controller always active after it is initialized.
  2. What is the best practice to stop any background controllers? My idea is to check the $location.path().

Update 1:

The controller is actually destroyed. But the operation update will invoke it by itself, so the operation will be called endless.

My current workaround will check whether the current location has been change. So it works. I'm looking for a more elegant way, if it exists.

.controller('View1Ctrl', function($scope, $http) {
  $scope.update = function(path) {
    $http.get('/api/foo')
      .success(function(data) { /* got new data */ })
      .error(function(data) { /* error occurred */ })
      .finally(function() {
        if (path === $location.path()) {
          setTimeout($scope.update, 1000, path);
        }
      });
  }
  $scope.update($location.path());
});

Update 2:

A better way is to watch destruction and cancel an ongoing timeout promise. Thanks @pankajparkar

.controller('View1Ctrl', function($scope, $http, $timeout) {
  var timeoutPromise;
  $scope.$on("$destroy", function(){
    $timeout.cancel(timeoutPromise);
  });
  $scope.update = function() {
    $http.get('/api/foo')
      .success(function(data) { /* got new data */ })
      .error(function(data) { /* error occurred */ })
      .finally(function() {
         timeoutPromise = $timeout($scope.update, 1000);
      });
  }
  $scope.update();
});
Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
stanleyxu2005
  • 8,081
  • 14
  • 59
  • 94
  • [Good read here](http://stackoverflow.com/questions/16094940/what-is-the-lifecycle-of-an-angularjs-controller) – Harben Feb 23 '15 at 18:13
  • http://stackoverflow.com/questions/28657287/passing-values-in-angular-js/28657470#28657470 Have a look at it – Pankaj Parkar Feb 23 '15 at 18:15

1 Answers1

3

I think you are mentioned ng-controller on the body tag or the parent of your ng-view, In your case you should load the controller from your $routeProvider that will handle it,

Config

app.config(function($routeProvider) {
  $routeProvider
    .when('/view1', {
      templateUrl: 'view1.html',
      controller: 'view1Ctrl' //load specific controller from here
    })
    .when('/view2', {
      templateUrl: 'view2.html',
      controller: 'view2Ctrl' //load specific controller from here
    })
    .otherwise({
      redirectTo: '/view1'
    });
});

HTML

  <div class="wizard">
    <ng-view></ng-view>
  </div>

Below are the answer of your questions.

  1. Now when $routeProvider load view1.html the view1Ctrl will exists, as soon as user navigates to view2.html the view1Ctrl will stop its working view2Ctrl will comes into a picture as you mentioned that inside your route configuration.
  2. You should always use $routeProvider or $stateProvider(angular-ui-router) to set up routing inside you application, and load templates and controller on basis of routing. No need to check $location.path()

Working Plunkr

Update

Your problem was with the repetitive function call, which was running in background even after controller scope has vanished from DOM. The best way to clear out this function while redirecting to other controller. I'd suggest you to put your $timeout promise(you used setTimeout changed it to $timeout) in one java script variable, and cancel that while leaving(unregistered the controller). While leaving controller $destroy event gets dispatched by angular, which is act like destruct-or of controller, you can use of it, you could cancel your $timeout promise inside that.

CODE

var timeoutPromise = setTimeout($scope.update, 1000);
$scope.$on("$destroy", function(){
    $timeout.cancel(timeoutPromise);
});

Plunkr with canceling promise of $timeout. Reference Link

Hope this could help you, Thanks.

Community
  • 1
  • 1
Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299