I have a web service which returns some data. To prevent code duplication I want to move http request call to angular service:
angular.module('abc', [])
.factory('def', function () {
return {
getData: function () {
return $http.post('/path/', {});
}
};
});
All is good, but necessary data is inside complicated object, and I have to write every time:
def.getData().then(function (response) {
scope.obj = response.data.qwe.rty.xyz;
});
What is the easiest way to return promise, which will send value of response.data.qwe.rty.xyz directly to successCallback? And I can write like this:
def.getData().then(function (obj) {
scope.obj = obj;
});
The call $http.post('/path/', {}) returns a promise on which you then call then(). Note that then() also returns a promise, so you can chain the calls. Your code could therefore look like this:
angular.module('abc', [])
.factory('def', function () {
return {
getData: function () {
return $http.post('/path/', {})
.then(function(response) {
return response.data.qwe.rty.xyz;
});
}
};
});
you can use the deferring behavior that implemented in the $q provider
like so :
angular.module('abc', [])
.factory('def', function ($q) {
return {
getData: function () {
var def = $q.defer
$http.post('/path/', {}).then(function(response){
def.resolve(response.data.qwe.rty.xyz)
});
return def.promise;
}
};
});
and use it in your controller like :
def.getData().then(function (response) {
scope.obj = response;
});
Related
I have this array I am getting through the following method:
var url= *url defined here*;
$scope.ViewProfile = function () {
$http.get(url)
.success(function (response) {
$scope.ProfileList = response;
$scope.FavNumbers = $scope.ProfileList[0].FavNumbers;
})
.error(function () {
});
}
I am required to edit the Fav Numbers list on the UI. and post it back to another url through http post url method. What I am stuck is with the concept of asynchronous calls, due to which I am unable to retrieve the favorite numbers list to be available for editing. Please help!
I have tried a method of using promises as follows:
app.factory('myService', function($http) {
var myService = {
async: function(url) {
var promise = $http.get(url).then(function (response) {
console.log(response);
return response.data;
});
// Return the promise to the controller
return promise;
}
};
return myService;
});
In my controller I am doing:
angular.module('JuryApp').controller('mycontroller', ['myService', function (myService) {
myService.async(url).then(function(d) {
$scope.data = d;
});
app.controller('MainCtrl', function( myService,$scope) {
// Call the async method and then do stuff with what is returned inside our own then function
myService.async().then(function(d) {
$scope.data = d;
});
});
But I keep getting the error 'd is not defined'. It keeps giving an error of some sort, where the debugger goes into an infinite loop or something.
You are overcomplicating it, I think. Async calls are actually pretty simple:
You're service:
app.factory("myService", ["$http", function($http) {
var MyService = {
getData: function(url) {
return $http.get(url); //$http returns a promise by default
}
};
return MyService;
})];
Your controller:
angular.module('JuryApp').controller('mycontroller', ['myService', function (myService) {
$scope.FavNumbers = [];
var url = "http://my.api.com/";
myService.getData(url).then(function(response) {
$scope.FavNumbers = response.data[0].FavNumbers;
});
}]);
That's all that you need to do.
I've got a decorator for '$q' in my angularJS that add some extra methods to it, in this way:
angular
.module('myApi', [])
.config(function ($provide) {
$provide.decorator('$q', function ($delegate) {
var defer = $delegate.defer;
$delegate.defer = function () {
var deferred = defer();
deferred.promise.success = function (fn) {
deferred.promise.then(function(response) {
fn(response.data, response.status, response.headers);
});
return deferred.promise;
};
return deferred;
};
return $delegate;
});
});
But the method disappears when I do this in the api:
var DataFactoryBase = {
get: function (url, headers) {
var dfr = $q.defer();
dfr.resolve( api_bridge ({
execute: function () {
return $q.resolve($http.get(url, {headers: headers}));
}
}));
//this line still holds the decorator method
var withSuccessMethod = dfr.promise;
//this line returns a promise without the decorator methods
var lostSuccessMethod = dfr.promise.then(handlerSuccessResponse, handlerErrorResponse);
return lostSuccessMethod;
}
}
function handlerSuccessResponse(response) {
//do stuff
return $q.resolve(response);
}
function handlerErrorResponse(response) {
//do stuff
return $q.reject(response.data);
}
How can I make .then also return a promise with the success method?
Found out promise and defer are two different things (though the latter uses the former). Changing the promise returned when calling .then requires accesing the underlying promise in the defer. Can be done with Object.getPrototypeOf()
angular
.module('myApi', []).config(function ($provide) {
$provide.decorator('$q', function ($delegate) {
var defer = $delegate.defer;
$delegate.defer = function () {
var deferred = defer();
Object.getPrototypeOf(deferred.promise).success = function(callback) {
/* code */
}
return deferred;
};
return $delegate;
});
});
I found this plnkr link on the web but I need use it with 2 or 3 more ajax calls which doesn't require an argument from the first ajax call. How can I do it with error handling?
var app = angular.module("app", []);
app.service("githubService", function($http, $q) {
var deferred = $q.defer();
this.getAccount = function() {
return $http.get('https://api.github.com/users/haroldrv')
.then(function(response) {
// promise is fulfilled
deferred.resolve(response.data);
return deferred.promise;
}, function(response) {
// the following line rejects the promise
deferred.reject(response);
return deferred.promise;
});
};
});
app.controller("promiseController", function($scope, $q, githubService) {
githubService.getAccount()
.then(
function(result) {
// promise was fullfilled (regardless of outcome)
// checks for information will be peformed here
$scope.account = result;
},
function(error) {
// handle errors here
console.log(error.statusText);
}
);
});
http://plnkr.co/edit/kACAcbCUIGSLRHV0qojK?p=preview
You can use $q.all
var promises=[
$http.get(URL1),
$http.get(URL2),
$http.get(URL3),
$http.get(URL4)
];
$q.all(promises).then(function(response){
console.log('Response of Url1', response[0]);
console.log('Response of Url2', response[1]);
console.log('Response of Url3', response[2]);
console.log('Response of Url4', response[3]);
}, function(error){
});
I have forked your plunkr with $q
First you should make deferred variable local for each ajax call you want to return a promise. So, you have to create 2-3 functions (as many as your ajax calls) and keep them in an array. Then you should use:
$q.all([ajax1,ajax2,ajax3]).then(function(values){
console.log(values[0]); // value ajax1
console.log(values[1]); // value ajax2
console.log(values[2]);}); //value ajax3
example:
function ajax_N() {
var deferred = $q.defer();
http(...).then((response) => {
deferred.resolve(response);
}, (error) => {
deferred.reject(error);
});
return deferred.promise;
}
$q.all([
ajax_1,ajax_2,ajax_3
]).then(function(values) {
console.log(values);
return values;
});
Use $q.all in this case. It will call getAccount and getSomeThing api same time.
var app = angular.module("app", []);
app.service("githubService", function($http, $q) {
return {
getAccount: function () {
return $http.get('https://api.github.com/users/haroldrv');
},
getSomeThing: function () {
return $http.get('some thing url');
}
};
});
app.controller("promiseController", function($scope, $q, githubService) {
function initData () {
$q.all([githubService.getAccount(), githubService.getSomeThing()])
.then(
function (data) {
$scope.account = data[0];
$scope.someThing = data[1];
},
function (error) {
}
);
}
});
I wrote a wrapper for the $http service in angular using a service. Why do i have to return bothe the http call and my result to have it available in a controller?
this is the function in the service:
this.fetchData = function(url, parameters)
{
if (parameters)
{
return $http.get(url, {params: parameters}).then(
function (response) {
console.log(response);
return response.data.data;
},
function (response) {
console.log(response);
});
}
else
{
return $http.get(url).then(
function (response) {
console.log(response);
},
function (response) {
console.log(response);
}
);
}
}
and this is where i call it in the controller:
test.fetchData('/jewelry-room/move-user.action', {user:2000, task:7}).then(
function (response) {
console.log(response);
},
function (response) {
console.log(response);
}
);
Because what you return from the factory is a promise: return $http.get().then(). Since your factory has the callback function inside then, so the promise is resolved. In this case, the function inside controller then block will not be called.
You need to return again in order to have access to the response data inside the controller.
Alternatively, just return $http.get() from the factory.
You could just return the promise to your controller by using $q:
var fetchData = function (url, params) {
if (params) {
var deferred = $q.defer();
$http.get(url, {params: params}).success(deferred.resolve).error(deferred.reject)
return deferred.promise;
} else {
var deferred = $q.defer();
$http.get(url).success(deferred.resolve).error(deferred.reject)
return deferred.promise;
}
}
Then inside your controller you can handle the promise.
I have multiple controllers on a page that use the same service, for the sake of example we will call the service USER.
The first time the USER.getUser() is called it does an $http request to GET data on the user. After the call is completed it stores the data in USER.data. If another call is made to USER.getUser() it checks if there is data in USER.data and if there is data it returns that instead of making the call.
My problem is that the calls to USER.getUser() happen so quickly that USER.data does not have any data so it fires the $http call again.
Here is what I have for the user factory right now:
.factory("user", function($http, $q){
return {
getUser: function(){
var that = this;
var deferred = $q.defer();
if(that.data){
deferred.resolve(that.data);
} else {
$http.get("/my/url")
.success(function(res){
that.data = res;
deferred.resolve(that.data);
});
}
return deferred.promise;
}
}
});
I hope my question makes sense. Any help would be much appreciated.
Does this work for you?
.factory("user", function($http, $q) {
var userPromise;
return {
getUser: function () {
if (userPromise) {
return userPromise;
}
userPromise = $http
.get("/my/url")
.then(function(res) {
return res.data;
});
return userPromise;
}
}
})
$http already returns the promise for you, even more, in 2 useful types: success & error. So basically, the option that #kfis offered does NOT catch errors and not flexible.
You could write something simple:
.factory('user', function($http) {
return {
getUser: function() {
$http.get('/my/url/')
.success(function(data) {
return data;
})
.error(function(err) {
// error handler
})
}
}
})