Extract data from $resource.get(...).$promise - angularjs

I use $resource to get data from Facebook's Graph api:
resource = $resource(
"https://graph.facebook.com/v2.2/:api/:id/:node/"
)
So for instance, I made a successful request to 'https://graph.facebook.com/v2.2/user.id/albums/' by:
resource.get({id:user_id, node: "albums", access_token: ....}).then(function(response)
{
console.log(response)
})
and the response shows (in Chrome dev tool console):
Resource
- $promise: Promise
- $resolved: true
- data: Array[9]
- 0: Object
- 1: Object2:
- length: 9
- __proto__: Array[0]
- paging: Object
- __proto__: Resource
So I naively try to add under console.log response another console.log response.data,
but it shows 'undefined'.
So I wonder how to extract the data object?
========================== EDIT ========================
It seems the reason being
resource.get({id:user_id, node: "albums", access_token: ....}).then(function(response)
{
console.log(response)
})
is chained after another resource request as follows:
FB.get_user().then(function(response) {
var user_id;
return user_id = response.id;
}).then(function(response) {
return self.albums = FB.resource.get({
id: user_id,
node: "albums",
access_token: Auth.get_user().social_account_access_token
});
}).then(function(response) {
console.log("response", response); # Log #1
return console.log("response.data", response.data); # Log #2
});
In this case Log #1 will log out the resource object with data being an array, while Log #2 gives undefined.
If I do not chain the then function, but put the last one inside the previous .then, I have the expected results:
FB.get_user().then(function(response) {
var user_id;
return user_id = response.id;
}).then(function(response) {
return self.albums = FB.resource.get({
id: user_id,
node: "albums",
access_token: Auth.get_user().social_account_access_token
}).$promise.then(function(response) {
console.log("A: response", response); # Log #1
return console.log("response.data", response.data); # Log #2
});
});
gives Log #1 the same result, while Log #2 is an array of 9 elements.
** So I wonder I is the problem of the original method?**

What's happening in your first attempt is that in your second then() you are returning the return value of FB.resource.get(), but this value is not a promise, so this then() resolves immediately, and processing moves on to the next then() before the data is done being retrieved. When you view the values in your Chrome debugger, you are stopping the execution long enough for the request to finish, and the data is populated when you observe it. (There is a term for this phenomenon, by the way.)
According to the notes on this pull request and this note in the developer's guide, you should be using instance.$promise if you want to chain off of a resource request. So your second approach that uses $promise is more or less the correct way to go about it.
Your code can be cleaned up a bit. Unless you have a reason to want a separate step to extract the FB user id and pass it to the next step, you can remove the first .then(). There is some other tidying up that you can do as well:
FB.get_user()
.then(function (response) {
var user_id = response.id;
// the value assigned to self.albums here is a (mostly) empty object that will
// be populated with data when the request finishes
self.albums = FB.resource.get({
id: user_id,
node: "albums",
access_token: Auth.get_user().social_account_access_token
});
return self.albums.$promise;
})
.then(function (response) {
// (avoid putting a [then] inside another [then] unless you need to)
console.log("A: response", response);
console.log("response.data", response.data);
return response.data;
});

Related

Handling Ajax response with success and without failure

The below code has both success and failure handling
jQuery.ajax({
type:"post",
dataType:"json",
url: myAjax.ajaxurl,
data: {action: 'submit_data', info: info},
success: function(data) {
successmessage = 'Data was succesfully captured';
$("label#successmessage").text(successmessage);
},
error: function(data) {
successmessage = 'Error';
$("label#successmessage").text(successmessage);
},
});
$(":input").val('');
return false;
However we are not following the above...We are following as below
jQuery.ajax({
type:"post",
dataType:"json",
url: myAjax.ajaxurl,
data: {action: 'submit_data', info: info},
success: function(data) {
if(data.responseType == 'success') {
// success
}
if(data.responseType == 'failure') {
// failure
}
}
});
$(":input").val('');
return false;
Is our approach is the correct or wrong approach ??
Basically every response will be success and show error message based on the response type
Please advise. We need to follow the best practice
data. responseType doesn't return a 'success' or 'failure'. It is contains an enumerated value which represents the type of response coming back to you like text, json, arrayBuffer etc..
Hence in the second code block both if statements will be exceuted to be false and nothing will be done with the response received.
I think you should go with the first approach because
Whether you are using raw JS or a library to implement this functionality, you'll have access to the state of the request i.e. whether the request was successful; met with an error and finally whether it has been completed.
Make proper use of these events and their respective callbacks to manipulate the UI for a better user experience. For example, if the request was unsuccessful, you'd want to update the user interface to reflect that their changes weren't successful while if it was successful, you'd want to tell them so. Don't keep the user waiting!
With jQuery, you'd make use of the success and error callbacks. You also get other callbacks such as complete and beforeSend to be invoked for apporopriate use.
$.ajax({
//Other code
success: function(msg)
{
// Update the UI here to reflect that the request was successful.
doSomethingClever();
},
error: function(msg)
{
// Update the UI here to reflect that the request was unsuccessful
doSomethingMoreClever();
},
complete: function(msg)
{
// Update the UI here to reflect completion
doSomethingEvenMoreClever();
}
});
take a look at this

Angular JS 1.X Access Resolved Promise Objects values

I have read a lot of posts on promises,resolving promises, and accessing the data however I cannot seem to. Following some posts on Stack Overflow has just caused errors, so I am not sure what exactly I am doing wrong.
I have a function like so:
function getJsonl() {
var deferred = $q.defer();
$http({
url: 'urlNotShownForSecurity',
dataType:"json",
method: 'GET',
data:{"requestId":"123"},
headers:{"Content-Type":"application/json","requestId":"123"},
}).success(function(data) {
deferred.resolve(data);
console.log(data)
}).error(function(error,status,headers,config) {
deferred.reject(error);
});
return Promise.resolve(deferred.promise);
}
Here I return a json promise that has been resolved resulting in a json object I believe.
Printing to console I get the following:
Inside data is the information I need, it looks like this:
data:Array[8]
0:Object
description:"My description paragraph"
I have tried things with the returned object in my controller like:
vm.result = data.data[0].description;
vm.result = data[0].description
I have tried many different approaches in the view as well to access but I get 2 blank li tags and that is it.
I would like to be able to access the data so I populate a table. So if I can use it with ng repeat that would be great, as well as being able to access without because some data is used in more than just the table.
Update
#DanKing, following your implementation I get the following output in console:
Now I am back with a promise object.
It looks to me as though you're fundamentally misunderstanding the nature of promises.
$http() is an asynchronous function - that means it doesn't complete straight away, which is why it returns a promise.
It looks to me as though you're trying to call $http() and then get the result back and return it from your getJson1() method, before $http() has finished executing.
You can't do that. Your getJson1() method should just return the promise, so your calling method can chain onto it - like this:
getJson1().then(function(data) {
// do some other stuff with the data
});
The whole point of promise chains is that they don't execute straightaway - instead you provide callback functions that will be executed at some indeterminate point in the future, when the previous operation completes.
Your getJson1() function just needs to do this:
return $http({
url: 'urlNotShownForSecurity',
dataType:"json",
method: 'GET',
data:{"requestId":"123"},
headers:{"Content-Type":"application/json","requestId":"123"},
});
getJsonl().then(function(data){
console.log(data);
},function(err){
console.log(err);
})
should work. Where is your $http request and where is your call to getJsonl() will also make a difference. So choose that carefully when implementation. If you are using this in a service then you will have to return the function result say
this.somefunction = function (){
return getJonl();
}
and in your controller inject the service and do the following
service.somefunction().then(function(data){
console.log(data);
},function(err){
console.log(err);
})
Ok, rewrote the answer as a complete component to show the moving parts.
$http returns a promise so your original getJsonl call can be simplified. Using your original $http parameters this should dump your API response to the screen if you use the <json-thing> tag:
angular.module('yourModuleName')
.component('jsonThing', {
template: '<pre>{{$ctrl.thing|json}}</pre>',
controller: function ($http) {
var $ctrl = this;
getJsonl()
.then(function (response) {
console.log(response); // we have the $http result here
$ctrl.thing = response.data; // allow the template access
}, function (error) {
console.log(error); // api call failed
});
// call backend server and return a promise of incoming data
function getJsonl() {
return $http({
url: 'urlNotShownForSecurity',
dataType: 'json',
method: 'GET',
data: { requestId: '123'},
headers: { 'Content-Type': 'application/json', requestId: '123'}
});
}
}
});

sometimes receiving 'null' on angular/ionic post from service - how to repeat http call?

In my ionic app I use a dataservice to get data.
On webview (ionic serve) the calls are always good. But when testing on ios device I receive null data sometimes (response from error callback).
I dont know why this is happening, it should return data. When I click again the data is received. It happens 1 out of 10 times. So what I want to do is repeat the call untill data is received but I dont know the best approach for this. Here is my code
In state resolve:
resolve: {
getNewOrders: function (OrderService) {
//get new orders
OrderService.setNewOrders();
}
}
In order service:
this.setNewOrders = function () {
$ionicLoading.show({ template: '<ion-spinner icon="ios"></ion-spinner><p style="margin: 5px 0 0 0;">Getting new orders..</p>'});
newOrders = false;
return $http({
url: api_url + "/get-new-orders",
method: 'POST',
headers: {'Content-Type': 'application/json; charset=UTF-8'}
}).then(function(response) {
if (response.data.status == 'success') {
if (response.data.returnData.length > 0) {
newOrders = response.data.returnData;
}
}
if (response.status == 'error' || response.status == 'tokenerror') {
AppService.error(response.status, response.errorMessages);
}
$ionicLoading.hide();
return response.data;
},
function(response) { // Error callback
//alert('ERROR - RELOAD DATA '+response);
console.log('ERROR - RELOAD DATA '+response);
setNewOrders(); //<<HERE I WANT TO REPEAT THIS FUNCTION IF NULL DATA IS RECEIVED
$ionicLoading.hide();
});
}
so in the error callback I want to reload the http call to get the data.
I dont know why sometimes null is returned, but when repeating the call it gets the data again. So I tought if I just repeat the call unitll data is received its ok.
But I dont know how to do this
It is not advised to make a recursive call as you might end up crashing your application. If it not getting data in 1 out 10 times, there must be something wrong, you should fix it. If you insist on using this hack, you should pass integar in params, and then in recalling the method
if(count< 5)
setNewOrders(count + 1);
If you return a promise from the error handler the result of that promise will become the result of the original promise.
What that means is that the error handler should return the result of the recursive call:
function(response) { // Error callback
//alert('ERROR - RELOAD DATA '+response);
console.log('ERROR - RELOAD DATA '+response);
return setNewOrders();
}
and if the next call is successful the response.data value will propogate back through the chain of calls.
However Haseeb is correct that you should also use a counter to limit the number of times you can recurse.

Local Node API not POSTing to Mongoose DB

Can someone please tell me why my POST method is not saving to my MongoDB via Mongoose?
My Angular controller
$scope.saveUpdate = function(id){
$http.post('/api/entry/' + id)
.success(function(data){
$scope.entry = data;
})
.error(function(data){
console.log('There was a problem saving your entry: ' + data);
});
// update page with remaining entries
$http.get('/api/entries').then(function(response){
$scope.entries = response.data;
});
}
My API
app.post('/api/entry/:entry_id', function(req, res){
if (req.params) {
Entries.findByIdAndUpdate({
_id : req.params,
// the properties we're updating and the new values
username: req.body.username,
date: req.body.date,
income: req.body.income
}, function(err, entry){
if (err) {
res.send(err) }
else {
res.send('Success!');
}
})
}
});
The submit button in the view
<button type="submit" class="btn" ng-click="saveUpdate(entry._id)">Update</button>
The updated entry hits the DOM when the button is clicked but when it hits the Angular core code it reverts back to its original state without updating the DB. No errors are thrown either.
There are a few things wrong in the code above:
The entire req.paramsobject is being passed to the _id field instead of req.params.entry_id
The way parameters are being passed to findByIdAndUpdate() is incorrect
The request body is never being sent over in your $http.post() but you're expecting the req.body to contain data in your route
req.params points to the whole params object on the request. You only want to get the ID from the params and then pass that into your mongoose model.
Assuming you're passing in the entry_id then you will pass your first condition if(req.params) since params will indeed exist. However, when you pass req.params to _id field of your Entries model you're actually passing in the whole object { entry_id: '123' } instead of just 123.
Additionally, the way you're passing in values to the findByIdAndUpdate method is incorrect. There are 4 params it will take findByIdAndUpdate(id, [update], [options], [callback]), id is the only required field. You're passing in the whole object to find based on id and update the values in a single argument. You need to break out entry_id from the fields you'd like to update.
app.post('/api/entry/:entry_id', function(req, res) {
// Param Existence Checking
if (!req.params.entry_id)
return res.status(400).send('an entry_id must be provided');
if (!req.body.username)
return res.status(400).send('a username must be provided');
if (!req.body.date)
return res.status(400).send('a date must be provided');
if (!req.body.income)
return res.status(400).send('an income must be provided');
var updateData = {
username: req.body.username,
date: req.body.date,
income: req.body.income
};
Entries.findByIdAndUpdate(req.params.entry_id, updateData, function(err, entry){
if (err)
return res.status(500).send(err)
return res.status(200).send('Success!');
})
});
Also based on sample code from your question, I don't see where you're passing in values to req.body when doing $http.put(). One thing for sure is that, if req.body doesn't contain username,date and income you would get undefined assigned to those fields.
To supply the request body via $http.post() pass it in to the second param data.
$http.post('/api/entry/' + id, {
username: 'username',
date: new Date(),
income: 10000.00
})
.then(function(res, status){
console.log(res.data);
})
.catch(function(err) {
console.log(err);
});
Additionally, don't use .success() in your promise chain, that approach is deprecated. You should use the A+ standard .then() and .catch() when handling your response.

Rectangular addResponseInterceptor data object undefined while has it in response object

Using Restangular, the get method/promise resolves but the result handed to .then() is empty...with console.log(data); showing undefined. I checked the network tab in chromium debug and the xhr request is good with 200 success...there is a full json response in the body.
Using addResponseInterceptor, I have found that the data argument is undefined, but the response argument shows the object containing the data property with the payload/body.
So, I am left scratching my head.....why is the data argument undefined while the response object properly contains the json payload/response in the response.data?
I need to resolve this so the result is passed to .then() on resolve.
createNode: function(node) {
var account = "9936";
var eventId = "0fd6afd9-4aa0-a5c9-ff0b3e60cdcf";
Restangular.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
console.log("````````````````");
console.log(data);
console.log(operation);
console.log(what);
console.log(url);
console.log(response);
console.log(deferred);
console.log("````````````````");
});
node.js:12
undefined node.js:13
get node.js:14
event node.js:15
/1.0/loadbalancers/account/9936/event/0fd6afd9-4aa0-a5c9-ff0b3e60cdcf node.js:16
^Object {data: Object, status: 200, headers: function, config: Object}
config: Object
data: Object
Automation: Object
Classification: Array[2]
ExecutionTimestamp: "2014-08-13T16:08:37.4676Z"
ID: "0fd6afd9-a5c9-ff0b3e60cdcf"
Incident: Object
LastStatus: "ENQUEUED"
Metadata: Object
Name: "Node Create"
RecordLogs: false
Source: "Device Lifecycle"
Stream: Object
Targets: Array[1]
Make sure all your response interceptors return the data at the end:
Restangular.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
// your code here
return data;
});
Not returning anything will set the data to undefined on following response interceptors calls.

Resources