AngularJs,使用$ interval定期刷新视图不会更新某些值

时间:2017-01-08 21:52:05

标签: javascript angularjs

想象一下,您有一个视图,其中填充了对某些服务的http调用,该服务返回要显示的对象列表。我想定期刷新这些数据。我找到$interval来完成这种行为。

问题在于我无法展示一个简单的" isLoading"每当我想刷新视图时屏幕。

我想到了类似的东西:

   viewModel.isLoading = true;
   viewModel.refreshView();
   viewModel.isLoading = false;

当然,isLoading绑定到一些带有角度的视图消息。这不起作用,属性总是错误的。我发现这是因为当$interval调用的函数退出时,angular会通知属性视图已更改,但退出isLoading时它始终为false。

如果使isLoading反映其变化,即使它在函数内部,我怎样才能实现?

Plunker片段(Angular 1.6.0):http://plnkr.co/edit/kIANiq6F0eM98KgHdr6i?p=preview

我的观点:

<head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.js"></script>
    <script src="testController.js"></script>
</head>

<body>

    <div ng-app="testApp">
      <div ng-controller="testController as viewModel">

          <h1>
          "IsLoading" value: {{ viewModel.isLoading }}
          </h1>

      </div>
    </div>

</body>

我的控制器:

(function() {

angular.module('testApp', [])
.controller("testController", testController);

function testController($interval) {

  viewModel = this;
  viewModel.isLoading = true;

  viewModel.refreshView = function () {

      viewModel.DoSomeLongRunningOperation();

  };

  viewModel.DoSomeLongRunningOperation = function() {
      // 
  }


   var invertPropertyTimer = $interval(function () {

    viewModel.isLoading = true;
    viewModel.refreshView();
    viewModel.isLoading = false;

   }.bind(this), 1000);


}

})();

5 个答案:

答案 0 :(得分:3)

DoSomeLongRunningOperation进行http通话?所以它应该返回Promise,而在then中,您应该在isLoading来电回复后将false更改为http

我认为你没有考虑过的其他事情 - 如果http呼叫比下一个间隔时间花费更多时间(那么你将同时有两个http呼叫)怎么办?我认为您应该在上一次refreshView之后使用$timeout致电refreshView

Here is a working example

答案 1 :(得分:3)

我不确定这个,但是使用promises呢?

您可以在refreshView函数中返回promise对象。这将有助于您在稍后的时间间隔内查看任务是否已在DoSomeLongRunningOperation功能中完成。

  viewModel.refreshView = function () {
  return new Promise(function(resolve, reject){
          viewModel.DoSomeLongRunningOperation();
          resolve();
      });
  };

在您的操作功能中执行一些任务。让我们说有一个需要200毫秒的操作。 (我使用了setTimeout但是angular也有自己的可测试的$ timeout服务。)

  viewModel.DoSomeLongRunningOperation = function() {
      //do your thing.  

      setTimeout(function(){
            console.log("timeoutends.")
      }, 200);
  }

在你的interfal中,用then()听取诺言并改变isLoading变量。在DoSomeLongRunningOperation func完成后,该承诺解析器将触发;

var invertPropertyTimer = $interval(function () {

  viewModel.isLoading = true;
    viewModel.refreshView().then(() =>{
      viewModel.isLoading = false;
    });

}.bind(this), 1000);

我没有检查它是否有效或语法是否正确。如果数据正在变化但视图不是,那么您可能需要使用$apply()

链接:

答案 2 :(得分:2)

使用Promise,并在promise的isLoading = false方法中设置then()!看到它正常工作HERE

(function() {

  angular.module('testApp', [])
    .controller("testController", testController);

  function testController($interval, $timeout) {

    viewModel = this;
    viewModel.isLoading = false;

    viewModel.someData = "Haven't loaded anything yet...";

    viewModel.refreshView = function() {

      viewModel.isLoading = true;

      viewModel.DoSomeLongRunningOperation();

    };

    viewModel.DoSomeLongRunningOperation = function() {
      //Create a Promise object.
      //This will likely be an $http.get() call.
      var longRunningOperation = $timeout(function() {
        return 'Some data retrieved at ' + new Date();
      }, 500);

      //This runs once the Promise has resolved
      longRunningOperation.then(function(data) {

        //Do something with the retrieved data
        viewModel.someData = data;

        //Now we're done loading!
        viewModel.isLoading = false;
      });
    }


    var invertPropertyTimer = $interval(viewModel.refreshView.bind(this), 3000);


  }

})();

答案 3 :(得分:2)

在你的plunker中,它无法正常工作,因为在$ interval函数完成后,angular会刷新DOM,而isLoading的值仍为false。

正如评论中所说的那样,想法是在承诺的解决方案上将标志加载设置为false。

如果您的刷新是通过HTTP进行的,并且您使用的是$ http服务,那么这将非常简单:

$http.get().then(function(){
    viewModel.isLoading = false;
});

对于您在长时间操作中想要的演示,我不得不伪造异步操作,我使用了$q

  viewModel.DoSomeLongRunningOperation = function() { 
      var defered = $q.defer();
      setTimeout(function(){ defered.resolve(); }, 300);
      return defered.promise;
  }

最后是间隔部分:

var invertPropertyTimer = $interval(function () {
    viewModel.isLoading = true;
    viewModel.DoSomeLongRunningOperation().then(function(){viewModel.isLoading = false;});
}.bind(this), 1000);

这是一个链接到弹药的链接&#34;闪烁&#34;如你所愿: http://plnkr.co/edit/xsivUm7yVNeLEivQUoLM?p=preview

答案 4 :(得分:0)

试试这个

viewModel.isLoading = true;
$timeout(function(){
  viewModel.refreshView();
  viewModel.isLoading = false;
}, 0);