Angular - How can i pass a parameter into a deferred promise? - javascript

Working on my first Angular app here so excuse me if question not clear.
I have a service which gets from my api using a group variable in the header.
var theReq = {
method: 'GET',
url: API + '/homeq',
headers: {
'group': 'mobile'
}
};
$http(theReq)
.then(function(data){
deferred.resolve(data);
})
self.getResults = function() {
return deferred.promise;
}
The issue I'm facing is with using the group variable that i specify rather than that preset one.
I can surely pass it into that function (i.e. self.getResults = function(groupToGet)) but how would it get from there to theReq that I process?
Any help appreciated.
Thanks.

You need to modify your function in following manner. $q is the service to create deferred objects. You need to inject it.
self.getResults = function(groupToSet) {
var deferred = $q.defer();
var theReq = {
method: 'GET',
url: API + '/homeq',
headers: {
'group': groupToSet
}
};
$http(theReq)
.then(function(data){
deferred.resolve(data);
})
return deferred.promise;
}
and you can use promise as
self.getResults("mobile").then(function(data) {
//success function here.
}).catch(function(error) {
//error function here
});

Related

is it possible not to execute the promise (.then ()) in the controller when there is an error in a web request?

I'm currently using a factory called http that when I invoke it, I make a web request. this receives as a parameter the url of the web request.
app.factory('http', function ($http) {
var oHttp = {}
oHttp.getData= function (url) {
var config={
method: 'GET',
url: url
}
return $http(config).then(function(data) {
oHttp.data=data.data;
},function(response) {
alert("problem, can you trying later please?")
});
}
return oHttp;
});
function HelloCtrl($scope, http) {
http.getData('https://www.reddit.com/.json1').then(function(){
if(http.data!=undefined){
console.log(http.data)
}
})
}
I would like the promise not to be executed on the controller if the result of the web request is not satisfied or there is a problem. is there any better solution? I want to avoid doing this every time I make a web request, or do not know if it is the best way (see the if):
//I am putting "1" to the end of the url to generate an error.
http.getData('https://www.reddit.com/.json1').then(function(){
//validate that the result of the request != undefined
if(http.data!=undefined){
alert(http.data.kind)
}
})
In my real project I make n web requests using my factory http, I do not want to do this validation always. I do not know if I always have to do it or there is another solution.
this is my code:
https://plnkr.co/edit/8ZqsgcUIzLAaI9Vd2awR?p=preview
In rejection handlers it is important to re-throw the error response. Otherwise the rejected promise is converted to a successful promise:
app.factory('http', function ($http) {
var oHttp= {};
oHttp.getData= function (url) {
var config={
method: 'GET',
url: url
}
return $http(config).then(function(response) {
̶o̶H̶t̶t̶p̶.̶d̶a̶t̶a̶=̶r̶e̶s̶p̶o̶n̶s̶e̶.̶d̶a̶t̶a̶;̶
return response.data;
},function(response) {
alert("problem, can you trying later please?")
//IMPORTANT re-throw error
throw response;
});
}
return oHttp;
});
In the controller:
http.getData('https://www.reddit.com/.json1')
.then(function(data){
console(data)
}).catch(response) {
console.log("ERROR: ", response.status);
});
For more information, see You're Missing the Point of Promises.
In Service
app.factory('http', function ($http) {
var oHttp = {}
oHttp.getData= function () {
return $http({
method: 'GET',
url: 'https://www.reddit.com/.json1'
});
}
return oHttp;
});
In controller
function HelloCtrl($scope, http) {
var httpPromise = http.getData();
httpPromise.then(function(response){
console.log(response);
});
httpPromise.error(function(){
})
}
So I tried this in codepen having ripped your code out of plinkr
https://codepen.io/PocketNinjaDesign/pen/oGOeYe
The code wouldn't work at all...But I changed the function HelloCtrl to a controller and it seemed happier....?
I also set response.data to default to an empty object as well. So that way if you're populating the data in the page it will be empty if nothing arrived. You can then in some instances on the site check the length if it's really required.
app.factory('http', function ($http) {
var oHttp = {}
oHttp.data = {};
oHttp.getData= function (url) {
var config = {
method: 'GET',
url: url
}
return $http(config).then(function(response) {
oHttp.data = response.data || {};
}, function(response) {
alert("problem, can you trying later please?")
});
}
return oHttp;
});
app.controller('HelloCtrl', function($scope, http) {
http.getData('https://www.reddit.com/.json').then(function(){
alert(http.data.kind);
})
});

Angular services: is it bad practice to assign response to an object or should I only use resolve

I have seen this code, which works for me but I wonder if it's bad practice to create an object inside the service- assign it to this and then to assign the response to the object in the success callback of the http get method.
.service("personDataService", function($http, $q) {
var person = this;
person.record = {};
var endPoint = 'https://api.something.com';
person.getInformation = function() {
var defer = $q.defer();
$http.get(endPoint)
.success(function(response) {
/*
here i'm assigning response to person.record and also using resolve.
but is this bad practice to assign response directly to person?
*/
person.record = response;
defer.resolve(response);
})
.error(function(err, status) {
defer.reject(err);
})
return defer.promise;
}
return person;
}
Then in my controllers code I am calling the personDataService.record directly to check if it's empty.
i.e.
Object.keys(personDataService.record).length
Is this bad practice to be using personDataService.album directly?
It would be better if instead of assigning a response to an object to use then method from inside your controller and have the response delivered there. Another thing that you shoud do is to remove the $http legacy promise methods success and error that have been deprecated and use the standard then method. This is an example of how to use then method.
angular.module('starter')
.factory('services', services);
function services($http) {
var services = {
someService: someService,
};
return services;
//someService service
function someService() {
var req = {
method: 'GET',
url: 'https://api.something.com',
headers: {
'Accept' : 'application/json',
'contentType': "application/json"
}
};
return $http(req);
};
}
Then from your controller call the service like this:
services.someService().then(
function(response) {
//do whatever is needed with the response
console.log(response);
},
function (error) {
console.log(error);
}
);

Angular Promise Response Checking

I am doing some http calls in Angular and trying to call a different service function if an error occurs. However, regardless of my original service call function return, the promise it returns is always "undefined". Here is some code to give context:
srvc.sendApplicantsToSR = function (applicant) {
var applicantURL = {snip};
var promise = $http({
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
method: 'POST',
url: applicantURL,
data: applicant
})
.success(function (data) {
return data;
})
.error(function (error) {
return [];
});
return promise;
};
Then, in the controller:
for (var applicant in $scope.applicants) {
$scope.sendATSError($scope.sendApplicantsToSR($scope.applicants[applicant]), applicant);
}
$scope.sendATSError = function (errorCheck, applicantNumber) {
if (angular.isUndefined(errorCheck)) {
console.log(errorCheck);
AtsintegrationsService.applicantErrorHandling($scope.applicants[applicantNumber].dataset.atsApplicantID);
}
};
However, it is always sending errors because every response is undefined. How can I differentiate between the two returns properly? Thank you!
Looking at angular documentation, the sample code is
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
based on that - your first code snippet should be
srvc.sendApplicantsToSR = function(applicant) {
var applicantURL = {
snip
};
return $http({
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
method: 'POST',
url: applicantURL,
data: applicant
});
};
As others have said, $http's .success() and .error() are deprecated in favour of .then().
But you don't actually need to chain .then() in .sendApplicantsToSR() as you don't need (ever) to process the successfully delivered data or to handle (at that point) the unsuccessful error.
$scope.sendApplicantsToSR = function (applicant) {
var applicantURL = {snip};
return $http({
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
method: 'POST',
url: applicantURL,
data: applicant
});
};
Now, in the caller (your line of code in the for loop), a promise is returned (not data) and that promise will, on settling, go down its success path or its error path. Exactly what happens on these paths is determined entirely by the callback functions you write in one or more chained .thens .
So what you need to write is a kind of inside-out version of what's in the question - with $scope.sendApplicantsToSR() on the outside and $scope.sendATSError() on the inside - and linked together with a .then().
for (var prop in $scope.applicants) {
var applicant = $scope.applicants[prop];
$scope.sendApplicantsToSR(applicant).then(null, $scope.sendATSError.bind(null, applicant));
}
// Above, `null` means do nothing on success, and
// `function(e) {...}` causes the error to be handled appropriately.
// This is the branching you seek!!
And by passing applicant, the error handler, $scope.sendATSError() will simplify to :
$scope.sendATSError = function (applicant) {
return AtsintegrationsService.applicantErrorHandling(applicant.dataset.atsApplicantID); // `return` is potentially important.
};
The only other thing you might want to know is when all the promises have settled but that's best addressed in another question.
You should return your promisse to be handled by the controller itself.
Simplifying:
.factory('myFactory', function() {
return $http.post(...);
})
.controller('ctrl', function(){
myFactory()
.success(function(data){
// this is your data
})
})
Working example:
angular.module('myApp',[])
.factory('myName', function($q, $timeout) {
return function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve('Foo');
}, 2000);
return deferred.promise;
}
})
.controller('ctrl', function($scope, myName) {
$scope.greeting = 'Waiting info.';
myName().then(function(data) {
$scope.greeting = 'Hello '+data+'!';
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="ctrl">
{{greeting}}!
</div>

unable to get data from $q into scope

I'm trying to bind some data being returned from an API to my scope using promises with $q, I am able to pull the data from the server without any issue (I can see JSON being returned using fiddler) however the $scope variable remains empty, any help would be greatly appreciated! Thanks in advance.
Code:
toDoListService.js
app.factory("toDoListService", function ($http, $q) {
var deferred = $q.defer();
return {
get: function () {
$http({ method: 'GET', url: '/api/todo/' }).
success(function (data) {
deferred.resolve(data);
}).
error(function (data, status, headers, config) {
deferred.reject(status);
});
return deferred.promise;
}
});
toDoListController.js
app.controller("toDoListController", function($scope, toDoListService){
$scope.toDoList = toDoListService.get();
});
First of all you should put var deferred = $q.defer(); in your get function, so that every get has it's own deferred object.
Second what get actually returns is a promise. So you need to access you data in this way:
app.controller("toDoListController", function($scope, toDoListService){
toDoListService.get().then(function(data){
$scope.toDoList = data;
});
});
Right now, your $scope.toDoList is bound to a promise. This means of binding used to work, but was deprecated in, I think, 1.2.
As Michael suggests, you must do:
app.controller("toDoListController", function($scope, toDoListService){
toDoListService.get().then(function(data){
$scope.toDoList = data;
});
});
Also, using $q is not required here at all, as $http returns a promise anyway. Therefore, you could just do:
app.factory("toDoListService", function ($http){
return {
get: function () {
return $http({ method: 'GET', url: '/api/todo/' });
}
};
});
You can simplify your code by using this:
toDoListService.js
app.factory("toDoListService", function ($http, $q) {
return {
get: function () {
return $http({ method: 'GET', url: '/api/todo/' });
}
}
});
toDoListController.js
app.controller("toDoListController", function($scope, toDoListService) {
toDoListService.get().then(function(response){
$scope.toDoList = response.data;
return response;
});
});
Be sure to return response in your success callback, otherwise chained promises would not receive it.

Using .always().error() syntax for Angular $q promises

I'm implementing just a thin wrapper around $http for our REST API, and I'm wanting it to return a promise in the same way as $http does (after I massage the data).
Here's my service:
Services.service('Item', ['$http', '$q', function($http, $q){
var deferred = $q.defer();
var getSuccess = function(data, status, headers, config){
var item = angular.copy(data);
item.primaryImage = 'https://my.cdn.com/' + item.meta.images[0].s3id;
if(item.meta.source_link !== null) {
item.sourceLink = item.meta.source_link.url;
}
deferred.resolve(item, data, status, headers, config);
};
var getError = function(data, status, headers, config) {
deferred.reject(data, status, headers, config);
};
this.get = function(userID, itemID) {
$http({
method: 'GET',
url: '/api/items/' + userID + '/' + itemID
}).success(getSuccess).error(getError);
return deferred.promise;
};
}]);
But from my understanding of the documentation, I have to use .then(success, error, always) rather than .success().error().always() like I can with $http.
Is it possible to implement promises in the same way that $http does? I would love to do this
var req = Item.get($routeParams.userID, $routeParams.itemID);
req.success(function(item){
window.console.log('Got an item!', item);
});
.error(function(item){
window.console.log('Damn. It failed.')
})
This question made me search for a bit after understanding what you actually wanted.
I made a plnkr showing how I solved this: http://plnkr.co/edit/LoCuwk26MEZXsugL1Ki5
Now, the important part is:
var promise = defered.promise;
promise.success = function(fn) {
promise.then(function(res) {
fn(res);
});
return promise;
};
promise.error = function(fn) {
promise.then(null, function(err) {
fn(err);
});
return promise;
};
return promise
This code comes straight from the angular source code. So I believe it is the way to go if you want to replicate that style.
I did notice an error in your code though. All services are singletons. Which means you only create one deferred object. You should create one on each call and use that.

Categories

Resources