Reputation: 802
I am making calls to the OpenWeatherMap API like this:
$scope.cities = [
{name: 'Phoenix,US'},
{name: 'Atlanta,US'},
{name: 'Honolulu,US'}
];
$scope.reload = function() {
$scope.items = [];
for (var i = 0; i < $scope.cities.length; i++) {
delete $http.defaults.headers.common['X-Requested-With'];
$http.get('http://api.openweathermap.org/data/2.5/weather?q=' + $scope.cities[i].name).success(function(data, status, headers, config) {
$scope. items.push(data);
});
}
$scope.name0 = $scope.items[0].name //error occurs here
};
I am getting the error "Property 'name' is undefined. I don't know why this error is occurring, since 'name' is a valid id in the OpenWeatherMap API.
Upvotes: 2
Views: 841
Reputation: 9409
I started on this before @NitishKumar posted their answer. Mine is similar in many respects, although they use a factory and Array.map(), which is probably better form overall. Meanwhile, I kept everything in the controller as you had it and used angular.forEach(). They also help you handle returned errors, which I didn't do in my code.
I still provide my answer (along with this Plunk) in case looking at your problem along with a few different solutions is helpful to you.
$scope.cities = [
{name: 'Phoenix,US'},
{name: 'Atlanta,US'},
{name: 'Honolulu,US'}
];
$scope.reload = function() {
var promises = [];
$scope.items = [];
angular.forEach($scope.cities, function(city) {
var deferred = $q.defer();
delete $http.defaults.headers.common['X-Requested-With'];
$http.get('http://api.openweathermap.org/data/2.5/weather?q=' + city.name).success(function(data, status, headers, config) {
deferred.resolve(data);
});
promises.push(deferred.promise);
});
return $q.all(promises);
};
$scope.reload().then(function(data){
$scope.name0 = data[0].name;
});
As mentioned in my initial comment on your question, your problem was that you were trying to set a scope variable to a value that had yet to be defined due to the asynchronous nature of AJAX requests / responses.
A good solution is to use promises, which help you to defer the setting of the scope variable until all AJAX requests have returned. AngularJS comes packaged with "a promise/deferred implementation inspired by Kris Kowal's Q", and the $q docs are worth a read.
Upvotes: 1
Reputation: 2400
The error occurs because the $scope.items
has not yet been populated. You can fix this by moving the assignment class inside the $http.get
function.
$scope.reload = function() {
$scope.items = [];
for (var i = 0; i < $scope.cities.length; i++) {
delete $http.defaults.headers.common['X-Requested-With'];
$http.get('http://api.openweathermap.org/data/2.5/weather?q=' + $scope.cities[i].name).
success(function(data, status, headers, config) {
$scope.items.push(data);
$scope.name0 = $scope.items[0].name //move this inside the $http.get
}
);
}
};
Upvotes: 0
Reputation: 4870
First Create a Factory
for $http
Request
myApp.factory('cityData',function($q,$http){
return function(cities){
var promises = cities.map( function(city){
var deffered = $q.defer();
delete $http.defaults.headers.common['X-Requested-With'];
$http({
url : 'http://api.openweathermap.org/data/2.5/weather?q=' + city.name,
method: 'GET'
})
.success(function(data){
deffered.resolve(data);
}).
error(function(error){
deffered.reject();
});
return deffered.promise;
});
return $q.all(promises);
}
});
Then Call it in Controller:
cityData($scope.cities).then(function(datas){
$scope.name0 = datas[0].name;
console.log($scope.name0);
});
See Demo Here
Upvotes: 3