Consider the code:
var myApp = angular.module('myApp', []);
The routes:
myApp.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'app.html',
controller:myAppController,
resolve:{
resolveData:function(Resolver){
return Resolver();
}
}
});
});
Resolve:
myApp.factory('Resolver', ['$http', function($http){
return function(){
return $http({url: '/someurl',method: "GET"}).then(function(data) {
// dependent call 1
$http({url: '/someotherurl',method: "GET" }).then(function(data) {
});
// dependent call 2
$http({url: '/someanotherurl',method: "GET" }).then(function(data) {
});
});
}
}]);
Above I have nested 2 calls inside one as they are dependent on the data returned by the parent call.
What I want to do: return the Resolver when all of them have completed and not just the parent call.
I cannot use $q.all() because 2 of the calls are dependent of the first call.
In short, myAppController must be loaded only after all the 3 calls have completed.
You should be using chaining promise and $q service to solve your problem .Just use the below sample code it should work
myApp.factory('Resolver', ['$http','$q', function ($http,$q) {
return function () {
var deferred = $q.defer();
$http({ url: '/someurl', method: "GET" }).then(function (data) {
return $http({ url: '/someurl', method: "GET" })
}).then(function (data) {
return $http({ url: '/someanotherurl', method: "GET" })
}).then(function (data) {
deferred.resolve(data);
});
return deferred.promise;
}
}]);
This works for me:
resolve : {
message: function($q, $route, Restangular) {
var msgId = $route.current.params.msgId;
var deferred = $q.defer();
Restangular.one('message', msgId).get().then(function(message) {
Restangular.one('file', message.audioFile.id).get().then(function (blob) {
message.blob = blob;
deferred.resolve(message);
});
});
return deferred.promise;
}
}
Related
I have 2 factories: ApiService and LocationService.
In ApiService i'd like to return the endpoint from an $http call that LocationService will use.
But it seems when the controller calls LocationService, it doesn't wait for the response from ApiService. Here is some snippet of code, in ApiService when I finally get it working I will cache it so I won't need to make a server call each time to get the endpoint:
services.factory("ApiService", ["$location", "$http", function ($location, $http) {
return {
getEndpointUrl: function () {
var endpoint;
$http({
method: 'GET',
url: '/site/apiendpoint'
}).then(function successCallback(response) {
endpoint = response.data;
console.log(endpoint);
return endpoint;
}, function errorCallback(response) {
console.error('Error retrieving API endpoint');
});
}
}
}]);
Here is the location service, it consumes ApiService:
services.factory("LocationService", ["$resource", "ApiService", function ($resource, apiService) {
var baseUri = apiService.getEndpointUrl();
return $resource(baseUri + '/location', {}, {
usStates: { method: 'GET', url: baseUri + '/location/us/states' }
});
}]);
When my controller tries to call LocationService.usStates the baseUri is undefined. What am I doing wrong here?
The reason is because your getEndpointUrl function is asynchronous, and it has no return value.
Since your LocationService uses $resource and depends on on the baseUri, I would suggest bootstrapping that data along with the initial page load and making it a constant like:
angular.module('yourModule').constant('baseUrl', window.baseUrl);
Then your service would inject it to create your resource:
services.factory("LocationService", ["$resource", "ApiService", "baseUrl", function ($resource, apiService, baseUrl) {
return $resource(baseUrl + '/location', {}, {
usStates: { method: 'GET', url: baseUrl + '/location/us/states' }
});
}]);
In ApiService, you're not actually returning a value from getEndpointUrl(). How about you return a promise from ApiService, and then consume that in LocationService in a synchronous fashion?
services.factory("ApiService", ["$location", "$http", function($location, $http) {
return {
getEndpointUrl: function() {
var endpoint;
return $http({
method: 'GET',
url: '/site/apiendpoint'
});
}
}
}]);
services.factory("LocationService", ["$resource", "ApiService", function($resource, apiService) {
return {
getLocations: function() {
return apiService.getEndpointUrl().then(function successCallback(response) {
var baseUri = response.data;
return $resource(baseUri + '/location', {}, {
usStates: { method: 'GET', url: baseUri + '/location/us/states' }
});
}, function errorCallback(response) {
console.error('Error retrieving API endpoint');
});
}
};
}]);
And then in your controller:
LocationService.getLocations().then(function(data) {
$scope.statesResult = data.result.states;
});
This question is related to another one.
Before I did added $ionicPlatform, my service working just fine, but now there is something wrong with $http.
Here is example of injectables:
(function () {
"use strict";
angular.module('service', ['ionic'])
.service('BBNService', ["$http", "$localStorage", "$ionicPlatform",
function ($http, $localStorage, $ionicPlatform) {
And using of $http and $ionicPlatform
this.tips = function () {
var url;
$ionicPlatform.ready(function () {
if (window.Connection) {
if (navigator.connection.type == Connection.CELL_4G || navigator.connection.type == Connection.WIFI) {
if (this.getDayId = 0)//If Sunday - retrieve updated tips
url = this.host + "/tips/";
else
url = "data/tips.json";//If not - use saved data
}
}
});
var request = $http({
method: "GET",
url: url
}).then(
function mySucces(response) {
return response.data;
},
function myError(response) {
return response.data;
});
return request;
};
You need to send back the promise, doing a return response.data is not gonna work.
var deferred = $q.defer();
var request = $http({
method: "GET",
url: url
}).then(
function mySucces(response) {
deferred.resolve(response.data);
},
function myError(response) {
deferred.reject(response.data);
});
return deferred.promise;
And at the place where you consume this service:
BBNService.tips().then(
function(data) { //success call back with data },
function(data) { //error call back with data }
);
Please let me know if you need more explanation on using $q; always happy to give more details.
I call getBookIDs from factory and by using the result I call getBookInfo from the same factory. but in the Console.log(bookInfo) it shows me the result of previous call!
how can I update the deferred.promise value before returning??
this is my controller
angular.module('myApp.products',[])
.controller('productController', function ($scope , MainFactory , $location) {
function getBookInfo(bookIDs){
MainFactory.getBookList(bookIDs)
.then(function (bookInfo) {
console.log(bookInfo)
})
}
MainFactory.getBookIDs()
.then(function (result) {
$scope.bookIDList = result;
getBookInfo($scope.bookIDList);
});
});
and this is my factory
app = angular.module('myApp');
app.factory("MainFactory", ['$soap', '$http', '$q', function ($soap, $http, $q) {
var viewFactory = {};
var deferred = $q.defer();
viewFactory.getBookIDs = function () {
//var bookIDs = [];
$http({
url: 'http://127.0.0.1/client.php?fn=getBooks',
method: "GET"
}).then(function success(response) {
deferred.resolve(response.data.result);
}, function myError(error) {
console.log('error', error);
});
return deferred.promise;
};
viewFactory.getBookList = function (bookIDs) {
$http({
url: 'http://127.0.0.1/client.php?fn=getBooksInfo&p1=' + bookIDs,
method: "GET"
}).then(function success(response) {
deferred.resolve(response.data.result);
}, function myError(error) {
deferred.reject(error);
});
return deferred.promise;
};
return viewFactory;
}]);
You should return a new promise for each of your service methods:
app.factory("MainFactory", ['$soap', '$http', '$q', function ($soap, $http, $q) {
var viewFactory = {};
viewFactory.getBookIDs = function () {
var deferred = $q.defer();
//var bookIDs = [];
$http({
url: 'http://127.0.0.1/client.php?fn=getBooks',
method: "GET"
}).then(function success(response) {
deferred.resolve(response.data.result);
}, function myError(error) {
console.log('error', error);
});
return deferred.promise;
};
viewFactory.getBookList = function (bookIDs) {
var deferred = $q.defer();
$http({
url: 'http://127.0.0.1/client.php?fn=getBooksInfo&p1=' + bookIDs,
method: "GET"
}).then(function success(response) {
deferred.resolve(response.data.result);
}, function myError(error) {
deferred.reject(error);
});
return deferred.promise;
};
return viewFactory;
}]);
Promises should not be reused (unless you wish to perform multiples tasks triggering the same resolve/reject... still, you should explicitly implement a promise aggregator for that, I think).
All angular services are singletons, so i guess the reason you got this bug is getBookIDs and getBookList share the same deferred
try change your factory to
app.factory("MainFactory", ['$soap', '$http', '$q', function ($soap, $http, $q) {
var viewFactory = {};
viewFactory.getBookIDs = function () {
//var bookIDs = [];
var deferred = $q.defer();
$http({
url: 'http://127.0.0.1/client.php?fn=getBooks',
method: "GET"
}).then(function success(response) {
deferred.resolve(response.data.result);
}, function myError(error) {
console.log('error', error);
});
return deferred.promise;
};
viewFactory.getBookList = function (bookIDs) {
var deferred = $q.defer();
$http({
url: 'http://127.0.0.1/client.php?fn=getBooksInfo&p1=' + bookIDs,
method: "GET"
}).then(function success(response) {
deferred.resolve(response.data.result);
}, function myError(error) {
deferred.reject(error);
});
return deferred.promise;
};
return viewFactory;
}]);
How can i get "pageid" inside resolve block?
For every url change i had to request the server, along with the "pageid"?
My code:
app.config(function($routeProvider){
$routeProvider
.when('/mainpage/:pageid',
{
controller:'ContentController',
resolve: {
data: function ($q, $http) {
console.log(window.location.hash)
var deferred = $q.defer();
$http({method: 'GET', url: mainURL}).then(function(data) {
deferred.resolve(data);
});
return deferred.promise;
}
},
templateUrl : 'app/partials/masterTemplate.html'
})
.otherwise({redirectTo:'/mainpage/home'});
});
You can do it like this:
data: function ($http, $routeParams) {
return $http({
method: 'GET',
url: mainURL,
params: {
pageid: $routeParams.pageid
}
})
.then(function(data) {
return data;
});
}
I have some code in my controller that was directly calling $http to get data.
Now I would like to move this into a service. Here is what I have so far:
My service:
angular.module('adminApp', [])
.factory('TestAccount', function ($http) {
var TestAccount = {};
TestAccount.get = function (applicationId, callback) {
$http({
method: 'GET',
url: '/api/TestAccounts/GetSelect',
params: { applicationId: applicationId }
}).success(function (result) {
callback(result);
});
};
return TestAccount;
});
Inside the controller:
TestAccount.get(3, function (data) {
$scope.testAccounts = data;
})
How can I change this so rather than passing the result of success back it
passes back a promise that I can check to see if it succeeded or failed?
Make your service to return a promise and expose it to service clients. Change your service like so:
angular.module('adminApp', [])
.factory('TestAccount', function ($http) {
var TestAccount = {};
TestAccount.get = function (applicationId) {
return $http({
method: 'GET',
url: '/api/TestAccounts/GetSelect',
params: { applicationId: applicationId }
});
};
return TestAccount;
});
so in a controller you can do:
TestAccount.get(3).then(function(result) {
$scope.testAccounts = result.data;
}, function (result) {
//error callback here...
});