当我从API中提取数据时,我想显示一个加载gif。 在某些情况下,我连接到同一视图上的多个资源,并且我不想使用$ http拦截器,所以我创建了这样的视图:
.controller('ViewOrderController', ['$routeParams', 'OrderService', 'AccountService', function (params, orderService, accountService) {
var self = this;
self.orderNumber = params.orderNumber;
self.loadingAccounts = true;
self.loadingOrders = true;
self.order = {};
self.account = {};
orderService.get(self.orderNumber, false).then(function (response) {
self.order = response.data;
self.loadingOrders = false;
accountService.get(self.order.accountNumber).then(function (response) {
self.account = response.data;
self.loadingOrders = false;
});
});
}])
但很快就会变得混乱,因为在某些情况下我会连接到4或5个不同的资源。 我的第一反应是将每个调用分成它自己的控制器,所以看起来有点像这样:
.controller('OrderController', ['$routeParams', 'OrderService', 'AccountService', function (params, orderService, accountService) {
var self = this;
self.loading = true;
self.orderNumber = params.orderNumber;
self.order = {};
orderService.get(self.orderNumber, false).then(function (response) {
self.order = response.data;
accountService.accountNumber = self.order.accountNumber; // Bind the account number to the service for use later
self.loading = false;
});
}])
.controller('AccountController', ['$scope', 'AccountService', function (scope, service) {
var self = this;
self.loading = true;
self.account = {};
scope.$watch(function () {
return service.accountNumber;
}, function (accountNumber) {
if (accountNumber) {
service.get(accountNumber).then(function (response) {
self.account = response.data;
self.loading = false;
});
}
});
}])
然后我开始遇到重复问题:
.controller('RecentOrdersController', ['OrderService', function (service) {
var self = this; // store our controller in a variable
self.loading = true; // This is what the ajax loading gif looks at to see if it should be displayed
self.orders = []; // Our orders array
service.recent(30).then(function (response) { // Get the 30 most recent orders
for (var i = 0; i < response.data.length; i++) {
var order = response.data[i]; // Store the order in a variable (for use later)
var desciption = service.getDescription(order); // Get our description
order.description = desciption; // Set our order description
self.orders.push(order); // Push our order to our array
}
self.loading = false; // Set our loading flag to false (hide the ajax loading gif);
});
}])
.controller('SyncFailureOrdersController', ['OrderService', function (service) {
var self = this; // store our controller in a variable
self.loading = true; // This is what the ajax loading gif looks at to see if it should be displayed
self.orders = []; // Our orders array
service.syncFailures(30).then(function (response) { // Get the 30 most sync failures
for (var i = 0; i < response.data.length; i++) {
var order = response.data[i]; // Store the order in a variable (for use later)
var desciption = service.getDescription(order); // Get our description
order.description = desciption; // Set our order description
self.orders.push(order); // Push our order to our array
}
self.loading = false; // Set our loading flag to false (hide the ajax loading gif);
});
}])
我的上一篇文章,有人说要将我的共享代码放入服务中,这就是我想要做的。 我想创建一个服务,告诉控制器何时加载或者每次调用完成时都会告诉控制器。我不知道如何处理这个问题。另外,我看过(经过几个小时的搜索)人们使用$ resource;这有什么需要吗?它能让工作更容易吗?
非常感谢任何帮助。
更新1
感谢@tommes我已经更新了他的小提琴,以准确显示我的目标:
https://jsfiddle.net/2mhq9crf/3/
希望有所帮助
答案 0 :(得分:1)
在angularjs中组合异步操作的一般方法是承诺( $ q )
你应该把你的api电话放在服务中(我的个人服务偏好是.factory(...)
)
见这个例子:
https://jsfiddle.net/2mhq9crf/
var myApp = angular.module('myApp',[]);
myApp.factory('myService', function($timeout, $q) {
// Stub of $http.get(...)
return function () {
var d = $q.defer();
$timeout(function () {
d.resolve("val!");
}, 1000);
return d.promise;
};
});
myApp.factory('myOtherService', function($timeout, $q) {
// Stub of $http.get(...)
return function () {
var d = $q.defer();
$timeout(function () {
d.resolve("val!");
}, 500);
return d.promise;
};
});
myApp.controller("MyCtrl", function ($scope, myService, myOtherService) {
$scope.loading = [];
$scope.vals = [];
// Add loading-specific promise-handlers
var loadThisPromise = function (p) {
// Add the promise to our list of loading promises
$scope.loading.push(p);
p.finally(function () {
// .finally is called even if the request fails
// Remove the promise from our list of loading
// promises, using object identity
$scope.loading.splice($scope.loading.indexOf(p), 1);
});
// Return promise for further promise handling
return p;
};
// Produce a function that always logs the given text
var logThis = function (str) {
return function (val) {
console.log(str);
// Remember to forward value for promise chaining
return val;
};
};
// Promise handler for pushing a value to the scope
var pushVal = function (val) {
$scope.vals.push(val);
return val;
};
// Add loading-specific promise-handlers and
// work with the promise from there
loadThisPromise(myService())
.then(pushVal)
.then(logThis("myService loaded!"));
loadThisPromise(myOtherService())
.then(pushVal)
.then(logThis("myOtherService loaded!"));
$scope.name = 'Superhero';
});
<body ng-app="MyApp">
<div ng-controller="MyCtrl">
<h2>Hello, {{name}}!</h2>
<tt style="color: red;" ng-show="loading.length > 0">LOADING...</tt>
<pre ng-bind="vals | json"></pre>
</div>
</body>
更新1
如果同一页面上有多个列表,包含单独的列表和加载状态,我会重用这样的控制器函数:
https://jsfiddle.net/2mhq9crf/4/
app.controller("AccountCtrl", ["OrderService", function (OrderService) {
ControllerFun.call(this, OrderService);
}]);
如果您希望在父控制器中具有组合加载状态,则应通过服务共享组合加载状态。
希望它有所帮助: - )
更新2
这是一个数据服务管理加载状态的解决方案,以及通过就地更新数据来响应数据: https://jsfiddle.net/2mhq9crf/8/
这或多或少是$resource
的工作方式。