想象一下,您有一个视图,其中填充了对某些服务的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);
}
})();
答案 0 :(得分:3)
DoSomeLongRunningOperation
进行http通话?所以它应该返回Promise
,而在then
中,您应该在isLoading
来电回复后将false
更改为http
。
我认为你没有考虑过的其他事情 - 如果http呼叫比下一个间隔时间花费更多时间(那么你将同时有两个http呼叫)怎么办?我认为您应该在上一次refreshView
之后使用$timeout
致电refreshView
。
答案 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);