我正在尝试发出一个$http
请求来获取我的一个JSON文件并使用我所有控制器中的数据。
我在egghead.io上看到如何在多个控制器之间共享数据,我还阅读了这个StackOverflow问题:“Sharing a variable between controllers in angular.js”。
但是,那里的答案不使用$http
模块。使用$http
时,控制器没有要处理的数据,并且在收到响应时已经太晚了。
然后我在StackOverflow上找到方法$q.defer
和这个问题:“AngularJS share asynchronous service data between controllers”
在那里发布的解决方案运行正常,但它有两个问题:
$http
请求以获取已在另一个控制器中使用的相同数据;和,then
功能。下面你可以看到我的代码:
controllers.js
'use strict';
/* Controllers */
function appInstallerListCtrl($scope, Data) {
$scope.apps = Data;
}
function appInstallerDetailCtrl($scope, $routeParams, Data) {
$scope.appId = $routeParams.appId;
$scope.apps = Data;
console.log($scope.apps); // <-- then function
console.log(Data); // <-- then function with $vv data returned but I can't access it
for (var i in $scope.apps) // <--- no way, baby!
console.log(i);
}
app.js
var app = angular.module('appInstaller', []);
app.factory('Data', function($http, $q) {
var defer = $q.defer();
$http.get('apps.json').then(function(result) {
defer.resolve(result.data.versions.version);
});
return defer.promise;
});
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/app', {templateUrl: 'partials/app-list.html', controller: appInstallerListCtrl}).
when('/app/:appId', {templateUrl: 'partials/app-detail.html', controller: appInstallerDetailCtrl}).
otherwise({redirectTo: '/app'});
}]);
我想要的是,在启动应用程序时,将执行$http
请求,并且将在整个应用程序中跨所有控制器使用响应。
由于
答案 0 :(得分:14)
我喜欢将我的数据存储在服务中,并向控制器返回一个承诺,因为通常你需要处理那里的任何错误。
app.factory('Data', function($http, $q) {
var data = [],
lastRequestFailed = true,
promise;
return {
getApps: function() {
if(!promise || lastRequestFailed) {
// $http returns a promise, so we don't need to create one with $q
promise = $http.get('apps.json')
.then(function(res) {
lastRequestFailed = false;
data = res.data;
return data;
}, function(res) {
return $q.reject(res);
});
}
return promise;
}
}
});
.controller('appInstallerListCtrl', ['$scope','Data',
function($scope, Data) {
Data.getApps()
.then(function(data) {
$scope.data = data;
}, function(res) {
if(res.status === 500) {
// server error, alert user somehow
} else {
// probably deal with these errors differently
}
});
}]);
在解决/拒绝承诺后注册的任何回调将立即使用相同的结果/ failure_reason解决/拒绝。一旦解决/拒绝,承诺就不能改变(其状态)。因此,第一个调用getApps()
的控制器将创建承诺。调用getApps()
的任何其他控制器将立即获得返回的承诺。
答案 1 :(得分:1)
由于您使用的是promise,因此要访问promise返回的数据,请使用回调语法
function appInstallerDetailCtrl($scope, $routeParams, Data) {
$scope.appId = $routeParams.appId;
Data.then(function(returnedData) {
$scope.apps=returnedData;
console.log($scope.apps);
for (var i in $scope.apps)
console.log(i)
});
}
确保这个
defer.resolve(result.data.versions.version);
resolve returns array,让上面的代码工作。或者看看数据中有什么,并调整控制器代码。
答案 2 :(得分:1)
我发现不确定天气的方式是否是最佳方法。
在HTML中
<body ng-app="myApp">
<div ng-controller="ctrl">{{user.title}}</div>
<hr>
<div ng-controller="ctrl2">{{user.title}}</div>
</body>
在Javascript中
var app = angular.module('myApp', []);
app.controller('ctrl', function($scope, $http, userService) {
userService.getUser().then(function(user) {
$scope.user = user;
});
});
app.controller('ctrl2', function($scope, $http, userService) {
userService.getUser().then(function(user) {
$scope.user = user;
});
});
app.factory('userService', function($http, $q) {
var promise;
var deferred = $q.defer();
return {
getUser: function() {
if(!promise){
promise = $http({
method: "GET",
url: "https://jsonplaceholder.typicode.com/posts/1"
}).success(function(res) {
data = res.data;
deferred.resolve(res);
})
.error(function(err, status) {
deferred.reject(err)
});
return deferred.promise;
}
return deferred.promise;
}
}
});
这只会产生1个HTTP请求。
答案 3 :(得分:0)
我的问题是我不想在加载另一个控制器之前等待resolve
,因为如果网络很慢,它会在控制器之间显示“滞后”。我的工作解决方案是通过ui-router
的{{1}}在控制器之间传递一个promise,而promise中的数据可以在第二个控制器中异步加载:
app.route.js - 将可用的参数设置为传递给SearchController,后者显示搜索结果
params
landing.controller.js - 用户添加搜索输入并提交的控制器
.state('search', {
url: '/search',
templateUrl: baseDir + 'search/templates/index.html',
controller: 'SearchController',
params: {
searchPromise: null
}
})
search.service.js - 从用户输入返回承诺的服务
let promise = SearchService.search(form);
$state.go('search', {
searchPromise: promise
});
search.controller.js - 其中搜索控制器
function search(params) {
return new Promise(function (resolve, reject) {
$timeout(function() {
resolve([]) // mimic a slow query but illustrates a point
}, 3000)
})
}