linking promises, or one promise triggers another
I'm building a weather app where I first have to get the users location, then make the request to get the weather.
So I have a GeolocationService
and a WeatherService
. My WeatherService
is currently calling the Geolocation
Service. How do I make the WeatherService
wait until it has the results from the GeolocationService
before making the HTTP request?
app.factory('GeolocationService',function($q,$window,$rootScope){ return { getLatLon: function(){ var deferred = $q.defer(); if(!window.navigator){ $rootScope.$apply(function(){ deferred.reject(new Error("Geolocation not available")); }); } else { $window.navigator.geolocation.getCurrentPosition(function(position){ $rootScope.$apply(function(){ deferred.resolve(position); }); }, function(error){ $rootScope.$apply(function(){ deferred.reject(error); }); }); } return deferred.promise; } }; }); app.factory("WeatherService", function ($q,$http,$rootScope, GeolocationService) { return { getWeather: function(){ var weather; var loc = new GeolocationService.getLatLon(); var lat= loc.lat || 37.4568202221774, lon= loc.lon || -122.201366838789 ; var units = ''; var url = 'http://api.openweathermap.org/data/2.5/forecast/daily?lat='+lat+'&lon='+lon+'&units='+units+'&callback=JSON_CALLBACK'; $http.jsonp(url) .success(function(data) { weather=data; return weather; }) .error(function(err){ weather=err; return err; }); } }; });
You just need to use the promise in your service and then chaine the promise. For sample I have a user with user.company_id and if I want get the name of the company I have to wait that the user is load. It the same that your situation.
this is my service:
angular.module('UserService', [])
.factory('UserService', function($q , $http, $rootScope,$timeout) {
var currentUserPromise = null;
var currentCompanyPromise = null;
return {
getCurrentUser: function() {
if (currentUserPromise === null) {
var config = {};
config.cache = true;
config.method = "GET";
config.url = "users/get_current_user";
currentUserPromise = $http(config)
.then(function(response) {
if (typeof response.data === 'object') {
return response.data.user;
} else {
// invalid response
return $q.reject(response.data);
}
}, function(response) {
// something went wrong
return $q.reject(response.data);
});
}
return currentUserPromise;
},
getCurrentCompany: function(company_id) {
if (currentCompanyPromise === null){
var config = {};
var company = {};
company.id = company_id;
config.cache = true;
config.method = "GET";
config.url = "/companies/show";
config.params = company;
currentCompanyPromise = $http(config)
.then(function(response) {
if (typeof response.data === 'object') {
return response.data.company;
} else {
// invalid response
return $q.reject(response.data);
}
}, function(response) {
// something went wrong
return $q.reject(response.data);
});
}
return currentCompanyPromise;
}
};
});
and in my controller I user this like this:
CONTROLLER :
var promiseCurrentUser = UserService.getCurrentUser();
promiseCurrentUser.then(function(user) {
$scope.currentUser = user;
UserService.getCurrentCompany(user.company_id).then(function(company){
$scope.companyName = company.name;
});
});
And What is cool with the promise is that it is resolve once.
I hope this will help you.
Your GeolocationService
's function getLatLon
is returning a promise. There is no need to call it with a new
operator.
Your getWeather
function should look something along the lines of:
app.factory("WeatherService", function ($q,$http,$rootScope, GeolocationService) {
return {
getWeather: function(){
var weather;
return GeolocationService.getLatLon().then(
function (loc) {
var lat= loc.lat || 37.4568202221774,
lon= loc.lon || -122.201366838789 ;
var units = '';
var url = 'http://api.openweathermap.org/data/2.5/forecast/daily?lat='+lat+'&lon='+lon+'&units='+units+'&callback=JSON_CALLBACK';
return $http.jsonp(url)
.success(function(data) {
weather=data;
return weather;
})
.error(function(err){
weather=err;
return err;
});
});
}
}
}
Here, we first call the GeolocationService.getLatLon()
to get a promise. Then we chain our processing as a chain to it. The success function will get the position
you resolve it with here deferred.resolve(position);
.
Also, you do not need to wrap the resolve
and reject
within an $apply
. Hence, your GeoLocationService
can be simplified to:
if(!window.navigator){
deferred.reject(new Error("Geolocation not available"));
} else {
$window.navigator.geolocation.getCurrentPosition(function(position){
deferred.resolve(position);
}, function(error){
deferred.reject(error);
});
}
链接地址: http://www.djcxy.com/p/77688.html
上一篇: 服务,工厂,过滤器等的依赖注入
下一篇: 链接承诺,或一个承诺触发另一个承诺