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
上一篇: 服务,工厂,过滤器等的依赖注入
下一篇: 链接承诺,或一个承诺触发另一个承诺
