当控制器变为后台(或无效)时需要停止正在进行的操作

时间:2022-12-29 16:59:01

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.

我正在编写我的第一个AngularJS应用程序。着陆页有两个链接#/ view1和#/ view2。每个链接都会调用单个控制器来单独呈现

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.

view1Ctrl将定期从服务器获取数据。我每隔X秒就可以在控制台中看到ajax调用。现在我点击#/ view2,应用程序应该使用view2Ctrl。我希望view1Ctrl不再从服务器获取数据。但实际上确实如此。

.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. 控制器在初始化后始终处于活动状态。

  3. What is the best practice to stop any background controllers? My idea is to check the $location.path().
  4. 停止任何后台控制器的最佳做法是什么?我的想法是检查$ 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

更好的方法是观察破坏并取消持续的超时承诺。谢谢@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();
});

1 个解决方案

#1


2  

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,

我认为你在body标签或ng-view的父级上提到了ng-controller,在你的情况下你应该从你的$ routeProvider加载控制器来处理它,

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. 现在当$ routeProvider加载view1.html时,view1Ctrl将存在,只要用户导航到view2.html,view1Ctrl将停止其工作view2Ctrl将进入你的路由配置中提到的图片。

  3. 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()
  4. 您应该始终使用$ routeProvider或$ stateProvider(angular-ui-router)在应用程序内部设置路由,并根据路由加载模板和控制器。无需检查$ 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.

你的问题是重复的函数调用,即使在控制器作用域从DOM中消失之后,它也在后台运行。重定向到其他控制器时清除此功能的最佳方法。我建议你把你的$ timeout承诺(你使用setTimeout将它改为$ timeout)放在一个java脚本变量中,并在离开时取消(取消注册控制器)。虽然离开控制器$ destroy事件会被angular调度,这就像破坏 - 或控制器,你可以使用它,你可以取消你的$ timeout承诺。

CODE

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

Plunkr with canceling promise of $timeout. Reference Link

Plunkr取消$ timeout的承诺。参考链接

Hope this could help you, Thanks.

希望这可以帮助你,谢谢。

#1


2  

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,

我认为你在body标签或ng-view的父级上提到了ng-controller,在你的情况下你应该从你的$ routeProvider加载控制器来处理它,

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. 现在当$ routeProvider加载view1.html时,view1Ctrl将存在,只要用户导航到view2.html,view1Ctrl将停止其工作view2Ctrl将进入你的路由配置中提到的图片。

  3. 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()
  4. 您应该始终使用$ routeProvider或$ stateProvider(angular-ui-router)在应用程序内部设置路由,并根据路由加载模板和控制器。无需检查$ 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.

你的问题是重复的函数调用,即使在控制器作用域从DOM中消失之后,它也在后台运行。重定向到其他控制器时清除此功能的最佳方法。我建议你把你的$ timeout承诺(你使用setTimeout将它改为$ timeout)放在一个java脚本变量中,并在离开时取消(取消注册控制器)。虽然离开控制器$ destroy事件会被angular调度,这就像破坏 - 或控制器,你可以使用它,你可以取消你的$ timeout承诺。

CODE

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

Plunkr with canceling promise of $timeout. Reference Link

Plunkr取消$ timeout的承诺。参考链接

Hope this could help you, Thanks.

希望这可以帮助你,谢谢。