Greetings to everyone.
I'm trying to get data returned from an $http on angular. I created a factory:
.factory('MyFactory', function($http, SKURL) {
return {
all: function(my_data) {
return $http({
method: 'POST',
url: SKURL.url,
data: "data=" + my_data,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
}
}
})
Then, in the controller, I write:
var n = MyFactory.all(my_data);
When I see console.log(n), I see the returned object is a promise: Promise {$$state: Object}. I see the data when I expand the object. But, when I try get n.$$state.value.data I get undefined. How can I get the data returned for the $http ?
In you controller, try the following instead:
var n;
MyFactory.all(my_data).then(function(response) {
n = response.data;
console.log(n); // this should print your data;
// do something with 'n' here.
}, function(err) {
// handle possible errors that occur when making the request.
});
Related
I bit new to Angular, using controller, factory that keeps methods for the $http requests.
--------------In Service------------------------------
factory.getContract = function(guid) {
return $http
.get(Configuration.apiurl + '/contracts/' + guid, { headers: {"accesstoken": 'XXXXXXXXXX'}})
.then(function (response) {
return response;
});
};
--------------- In Controller ------------------
$scope.getContract = function (guid) {
ContractService.getContract(guid).then(
function (response) {
var data = response.data;
$scope.contract = {
contract_status: data.contract_status,
car: data.car,
properties: data.data
};
},
function (response) {
console.log('Error while loading the contract,', response);
}
);
};
if ($state.includes('contracts.edit')) {
$scope.getContract($stateParams.guid);
// In this controller, i check if requesting route is the Edit then get contract data. When i do this it works and fill the form with correct information. BUT AS I TRY TO ACCESS $scope.contract in console it says undefined
console.log($scope.contract);
}
What is wrong with my code?
$http.get is returning Promise, so just remove .then part from your factory if you want to execute callback inside controller:
factory.getContract = function(guid) {
return $http.get(Configuration.apiurl + '/contracts/' + guid,
{ headers:
{"accesstoken": 'XXXXXXXXXX'}
});
}
Hey I want to change the data before sending it with ngResource (build FormData object). I do everything as in the examples that I found, however I can't make them work. Here is my code:
My controller where I set the data and try to send them:
var vm = this;
vm.application = new Application();
vm.application.title = 'Test title';
Application.save({}, vm.application, function(){
});
My service:
function application(ApiBaseUrl, $resource) {
var actions = {
'save': {
metod: 'POST',
url: ApiBaseUrl + "/applications",
headers: { 'Content-Type': false },
transformRequest: function (data) {
console.log(data); //Returns 'undefined'
return data;
}
}
};
return $resource(ApiBaseUrl + "applications/:id", {}, actions);
}
In the function transformRequest data object is always marked as 'undefined'. Am I doing something wrong? Is there a better way to edit the data before sending it?
The problem was I had
metod: 'POST'
when I should have used:
method: 'POST'
I have a method seatClicked() that calls getUserID() to get the user id corresponding to the session atribute 'user'. There is a table that contains the username and user id(unique). The following is the definition of seatClicked()
$scope.seatClicked = function() {
promise = $scope.getUserID();
promise.then(function(results){
$scope.seatID.userID = results; // store the user id in $scope.seatID.userID
});
}
This is the definition for getUserID()
$scope.getUserID = function() {
var deferred = $q.defer();
$http({
method : 'POST',
url : 'http://localhost:8080/AirlineApp/getUserID',
headers : {
'Content-Type' : 'application/json'
}
}).then(function(data){
alert("userID:"+data)
deferred.resolve(data);
})
return deferred.promise;
};
The variable 'results' returned by $http.then() is always undefined, whereas if I use $http.success() I am able to retrieve the user id.
I want to fetch the user id before further processing. Is there any way for the function to wait till the data is fetched from the database?
P.S. I tried callback as well, no luck.
Edit: I am able to fetch the id and store it (thanks all), but it takes much longer than the time taken to execute my next operation(not presented here). Can I stall that operation till I am assured of the id?
what we did in our project, added PromiseUtils service for any REST calls
.service("PromiseUtils", function($q) {
return {
getPromiseHttpResult: function (httpPromise) {
var deferred = $q.defer();
httpPromise.success(function (data) {
deferred.resolve(data);
}).error(function () {
deferred.reject(arguments);
});
return deferred.promise;
}
}
})
and use it nice and easy
var anyCall = $http({
method: 'POST',
url: 'http://localhost:8080/AirlineApp/getUserID',
headers: {
'Content-Type': 'application/json'
}
});
PromiseUtils.getPromiseHttpResult(anyCall).then(function(result){
console.log("result", result);
})
or
PromiseUtils.getPromiseHttpResult($http.get('/api/get/call'))
.then(function(result){
console.log("result", result);
})
PromiseUtils.getPromiseHttpResult($http.post('/api/post/call', data))
.then(function(result){
console.log("result", result);
})
if you need error() function, just add as second parameter
PromiseUtils.getPromiseHttpResult($http.get('/api/get/call'))
.then(function(result){
console.log("result", result);
}, function (arguments) {
console.log("fail", arguments);
})
$http returns a special promise different from the standard promise like here https://github.com/promises-aplus/promises-spec
If you use $http you need to retrieve your data like this :
$http
.success(success)
.error(error) ...
But you can use standard promise by wrapping the $http promise in your service using $q like this :
var defer = $q.defer();
var http = $http({
url: SharedFactory.endPoint + '/stats',
method: 'GET',
params: params
});
http.success(function(stats) {
defer.resolve(stats);
})
.error(function() {
defer.reject("Failed to get stats");
});
return defer.promise;
I want create 1 service where i can POST the data and on success i can again GET the data and update the $scope.variable??
How to do that?
I've tried this way:
angular.module('mvc')
.factory('ajaxService', function($http) {
return {
getAjaxData: function(response) {
$http.get(url).success(response);
return response;
},
postAjaxdata: function(postData){
$http({
method: "post",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
url: url,
data: data
})
.success(function(response){
ajaxService.getAjaxData(function(response) {
$scope.foo = response;
});
});
}
}
});
Capture this in postAjaxdata() to be used in the success callback to call getAjaxData().
You don't have access to the scope inside of the service (nor do you want to access it from a service). The Angular convention is to return a promise to the controller so that it can apply the response value to the scope when the promise is resolved. You can also do this using callbacks (to be consistent with the code that was posted). Here, I've added a callback to postAjaxdata()...
angular.module('mvc')
.factory('ajaxService', function($http) {
return {
getAjaxData: function(successCallback) {
$http.get(url).success(successCallback);
return successCallback;
},
postAjaxdata: function(postData, successCallback){
var that = this;
$http({
method: "post",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
url: url,
data: data
})
.success(function(){
that.getAjaxData(successCallback);
});
}
}
});
The controller should look something like this...
function controller ($scope, ajaxService) {
// ...
ajaxService.postAjaxdata(postData, function (response) {
$scope.foo = response;
});
}
The main issue is that you can't set scope variables in the way you attempted to from the service.
You could instead use the $q service to return a promise which, when resolved, is set to your $scope.foo variable:
.factory('ajaxService', function($http, $q) {
var ajaxService = {
getAjaxData: function() {
return $http.get(url);
},
postAjaxdata: function(postData){
var deferred = $q.defer();
$http({
method: "post",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
url: url,
data: postData
})
.success(function(){
deferred.resolve(ajaxService.getAjaxData());
});
return deferred.promise;
}
};
return ajaxService;
});
You'll also notice that I set the body of your factory to a named variable, which you can then use to call functions internally (as you did with ajaxService.getAjaxData()) before returning.
Then, in your controller, you could set your scope variable like this:
.controller('MyController', function($scope, ajaxService){
ajaxService.postAjaxdata().then(function(results){
$scope.foo = results.data;
})
})
Working Plunker
Note: my answer is not entirely dissimilar to Anthony Chu's. I noticed that he posted his just before mine, but I went ahead anyway since mine takes a slightly different approach, utilizing promises instead of callbacks.
I have two $http posts that each post arrays of objects in a loop. The problem is that the second $http post is reliant on the first one completing. Is there a way to make them not async calls? I tried to used deferred but something is wrong in it as it is not working. It still fires group saving while tag saving is going on.
Angular:
var deferred = $q.defer();
var all = $q.all(deferred.promise);
for (var property in data.tagAdded) {
if (data.tagAdded.hasOwnProperty(property)) {
$http({
method: "POST",
url: '/api/projects/' + data.Project.Id + '/tags',
data: ({ Name: data.tagAdded[property].tag.Name })
}).success(function (response) {
deferred.resolve(response);
data.tagAdded[property].tag.Id = response.Data[0].Id;
data.tagAdded[property].tag.ProjectId = response.Data[0].ProjectId;
}).error(function (response) {
tagError = true;
$.jGrowl("Error saving new tags. Contact support.", { header: 'Error' });
});
}
}
deferred.promise.then(function() {
console.log(data);
});
all.then(function() {
groups.forEach(function(group) {
$http({
headers: { 'Content-Type': 'application/json; charset=utf-8' },
method: "POST",
url: '/api/projects/' + data.Project.Id + '/recruiting-groups',
data: angular.toJson(group, false)
}).success(function(response) {
}).error(function(response) {
recError = true;
$.jGrowl("Error saving recruiting group. Contact support.", { header: 'Error' });
});
});
});
Going without promises is totally not what you want to do here. In fact, this is exactly the kind of situation where promises shine the most! Basically, you weren't using $q.all properly. You can just pass it a list of promises, and it will be resolved when they are all resolved. If any one of them fails, it will yield a rejected promise with the same rejection as the first one that failed. You can of course swallow that rejection via a .catch invocation that returns anything other than a $q.reject value.
I reimplemented what you had using promises. Both .success and .error are fairly limited, so I used the traditional .then and .catch methods here.
/**
* Here we define a function that takes a property, makes a POST request to
* create a tag for it, and then appends the promise for the request to a list
* called tagRequests.
*/
var tagRequests = [];
var createTag = function(property) {
tagRequests.push($http({
method: "POST",
url: '/api/projects/' + data.Project.Id + '/tags',
data: ({ Name: data.tagAdded[property].tag.Name })
}).then(function(response) {
var responseData = response.data;
data.tagAdded[property].tag.Id = responseData.Data[0].Id;
data.tagAdded[property].tag.ProjectId = responseData.Data[0].ProjectId;
return responseData;
}).catch(function (err) {
var errorMsg = "Error saving new tags. Contact support.";
$.jGrowl(errorMsg, { header: 'Error' });
// If we don't want the collective promise to fail on the error of any given
// tag creation request, the next line should be removed.
return $q.reject(errorMsg);
}));
};
/**
* We then iterate over each key in the data.tagAdded object and invoke the
* createTag function.
*/
for (var property in data.tagAdded) {
if (Object.prototype.hasOwnProperty.call(data.tagAdded, property)) {
createTag(property);
}
}
/**
* Once all tag requests succeed, we then map over the list of groups and
* transform them into promises of the request being made. This ultimately
* returns a promise that is resolved when all group POST requests succeed.
*/
$q.all(tagRequests)
.then(function(tagsCreated) {
return $q.all(groups.map(function(group) {
return $http({
headers: { 'Content-Type': 'application/json; charset=utf-8' },
method: "POST",
url: '/api/projects/' + data.Project.Id + '/recruiting-groups',
data: angular.toJson(group, false)
}).then(function(response) {
return response.data;
})
.catch(function(err) {
var errorMsg = "Error saving recruiting group. Contact support.";
$.jGrowl(errorMsg, { header: 'Error' });
// If we want this collective promise to not fail when any one promise is
// rejected, the next line should be removed.
return $q.reject(errorMsg);
});
}));
});
I highly suggest brushing up on Promises in general, and then taking another look at the $q documentation. I've also written this blog post on the way promises work in Angular and how they differ from most promise implementations.
This is exactly what promises do. Angular uses Kris Kowal's Q Library for promises. Check out the Angular docs page, has a perfect example of the promise pattern. Basically you would do the first call, then once it's promise returns success, make the second call.
I had to alter my code a bit, and get some coworker team work. I went completely without promises.
I use a counter to track when counter = 0 by adding to the counter then upon success/fail i decrement from the counter taking it backwards for each completed transaction. When counter is at 0 I am done then call my next bit $http post.
Angular Deferred:
var counter = 0;
var tags = [];
for (var property in data.tagAdded) {
if (data.tagAdded.hasOwnProperty(property)) {
tags.push({ Name: property });
}
}
if (tags.length == 0) {
groupInsert();
} else {
tags.forEach(function (tag) {
counter ++;
$http({
method: "POST",
url: '/api/projects/' + data.Project.Id + '/tags',
data: ({ Name: tag.Name })
}).success(function (response) {
console.log(response)
counter--;
data.tagAdded[property].tag.Id = response.Data[0].Id;
data.tagAdded[property].tag.ProjectId = response.Data[0].ProjectId;
if (counter == 0) {
groupInsert();
}
}).error(function (response) {
counter--;
tagError = true;
$.jGrowl("Error saving new tags. Contact support.", { header: 'Error' });
if (counter == 0) {
groupInsert();
}
});
});
}
function groupInsert() {
groups.forEach(function (group) {
console.log(group)
$http({
headers: { 'Content-Type': 'application/json; charset=utf-8' },
method: "POST",
url: '/api/projects/' + data.Project.Id + '/recruiting-groups',
data: angular.toJson(group, false)
}).success(function (response) {
}).error(function (response) {
recError = true;
$.jGrowl("Error saving recruiting group. Contact support.", { header: 'Error' });
});
});
}