Checking if an Angular resource response is empty - angularjs

I have a service that returns a promise. I would like to check if the value returned is an empty object. How can I achieve this. I guess I need to extract the returned value from the promise object somehow.
Here's my resource:
app.factory('Auth', ['$resource',
function($resource) {
return $resource('/user/identify', {}, {
identify: {
url: '/user/identify'
},
});
}
]);
Then in a service:
Auth.identify(function(data) {
// This always passes since data contains promise propeties
if (!_.isEmpty(data)) {
}
});
A console log of data gives:
Resource
$promise: Object
$resolved: true
__proto__: Resource
I can check for expected properties when the object is not empty but would like a more generic method.

To unwrap the return value you can access the promise directly:
Auth.identify()
.$promise
.then(function(data) {
if (!_.isEmpty(data)) {
// ...
}
});

You're so close. You shouldn't call the response "data" when it is in fact a Resource object, which looks a lot like the Resource object you posted:
$resource('/api/...').get({...}).then(function(response) {
if (response.data) {
// the response has a data field!
}
}
// note: this is using query(), which expects an array
$resource('/api/...').query({...}).then(function(response) {
if (response.length > 0) {
// the response data is embedded in the response array
}
});

Related

How to get value from PROMISE in angular js $http service

How can get value from the Promise return by $http service
>d {$$state: Object}
$$state: Object
status: 1
value: Array[1]
__proto__: Object
__proto__: Object
How to get the value in the d object
s.states = '';
$http.get('/api/random').then(function(response) {
s.states = response;
}, function(error) {
}).finally(function() {
})
console.log(s.states);
which shows the above result. $$state so how can get the value from it?
As suggested above:
promise.then(function(value) {
// Value contains the data received in the response
}, function(error) {
// This is called when error occurs.
}
)
The promise itself does not contain a value. It returns the value in the future ("promises" to return a value) when it's available. And when it becomes available (or not), one of two callbacks passed to then() methods gets triggered.
So basically, you should make calls like this:
$http.get('/api/random').then(function(response) {
// Do some stuff with response.
});
You can pass a callback to finally() method callback, which will be run regardless of success or error in promise.
$http.get('/api/random').then(function(response) {
// This one is triggered in case of successful response.
}, function(error) {
// This code runs in case of error
}).finally(function() {
// And this block will be triggered anyway after the promise returns.
});

Passing 'filter' parameter to angular resource (DreamFactory rest api)

I am having an issue with query parameters from my AngularJS app
I am reading documents from MongoDB using DreamFactory rest api like this:
.service('Servant', ['$resource', function($resource) {
// define and return $resource
return $resource('https://mydsp.cloud.dreamfactory.com:443/rest/mongodb/tablename',
{
// set params to bind too
app_name: 'myapp',
fields: '#fields',
limit: '#limit',
offset: '#offset',
filter: '#filter'
},
{
// set update method to 'PUT'
update: {
method: 'PUT'
}
}
)
}]);
This all works great when I set filter like "parameter=value" but I failed to find a way of passing more complicated filter param in JSON format as described here, using $in parameter etc. Does anyone know the right syntax for this?
EDIT:
just tried something like
filter = angular.toJson("{'parameter':{$in:['value1','value2']}}")
with no success...
First...drop the port from your service url. 'https' for dreamfactory specifies port 443. No need for you to do it explicitly. Second...You should be able to pass a SQL style filter as a string in your params. When you set up your $resource the way you have you should be able to pass a params object to it. No need to stringify or toJson anything. DreamFactory should handle it. For example...
Here is your service:
.service('Servant', ['$resource', function($resource) {
return $resource('https://mydsp.cloud.dreamfactory.com/rest/mongodb/tablename',
{
app_name: 'myapp',
fields: '#fields',
limit: '#limit',
offset: '#offset',
filter: '#filter'
},
{
update: {
method: 'PUT'
}
}
}]);
Calling that service with a params object:
// the 'parameter' value in our filter string should relate to a field and/or property
scope.paramsObj = {
fields: '*',
limit: 10,
offset: 0,
filter: 'parameter in (5,15)'
}
// call service and handle promise returned by $resource
Servant.get(scope.paramsObj).then(
function(result) {
// handle success
// like assign to a var or something
// here we just log it
console.log(result)
},
function(error) {
// handle error
// probably should throw an error here
// but we just log it here
console.log(error);
});
EDIT
Ok. So...it should work with SQL style filter strings. An issue has been logged with DreamFactory. In the mean time you can create a custom $resource action to handle the filters and tunnel your GET request through a POST. Easier then it sounds. See code below.
Here is the service with custom action
.service('Servant', ['DSP_URL', '$resource', function (DSP_URL, $resource) {
return $resource(DSP_URL + '/rest/mongohq/Colors', {
// params to bind to
app_name: YOUR_APP_NAME_HERE,
fields: '#fields',
limit: '#limit',
offset: '#offset'
}, {
// custom $resource action
'getFiltered': {
// set our method to post because we have to post
// our filter object
method: 'POST',
// We can transform the data before the post.
// In the circumstance we do need to stringify
// So that's what we do here.
transformRequest: function (data) {
return JSON.stringify(data);
}
}
})
}]);
Here is the controller:
.controller('MongoCtrl', ['$scope', 'Servant', function ($scope, Servant) {
// Create a params object
// This requests all fields.
// And we explicitly set the method to
// GET. We are tunneling a GET request
// through our POST because our filter
// needs to be posted but we really want a GET.
$scope.params = {
fields: '*',
method: 'GET'
};
// Call our Service with our custom $resource action
Servant.getFiltered(
// Send our params
$scope.params,
// Send our filter as post data
{
"filter": {
"color": {
"$in": ["blue", "white"]
}
}
},
// handle success
function (data) {
console.log(data)
},
// handle error
function (error) {
console.log(error)
})
}])
I guess you should stringify your filter data:
resource.update( {
filter: JSON.stringify( {qty:{$in:[5,15]}} )
});
Or in this way:
resource.get({id:123}, function() {
resource.filter = JSON.stringify( {qty:{$in:[5,15]}} );
resource.$update();
});

Get response header in then() function of a ngResource object's $promise property after resource resolved?

I'm willing to retrieve the response header of a resource request, cause I've put pagination information and something else in it rather than the response body, to make the REST api clear.
Though we can get it from the success / error callback like below:
Object.get({type:'foo'}, function(value, responseHeaders){
var headers = responseHeaders();
});
Where 'Object' is my resource factory service.
Further, when I'm trying to make the route change after required resources resolved, I've tried this:
.when('/list', {
templateUrl: 'partials/list.html',
controller: 'ListCtrl',
// wait for the required promises to be resolved before controller is instantialized
resolve: {
objects: ['Object', '$route', function(Object, $route){
return Object.query($route.current.params).$promise;
}]
}
})
and in controller, just inject "objects" instead of Object service, because it's resolved and filled in with real data.
But I got problem when I try to get headers info from the "objects" in controller.
I tried objects.$promise.then(function(data, responseHeaders){}), but responseHeader was undefined.
How can I change the $resource service's behavior so that it throws the responseHeader getter into the $promise then() callback function?
My service "Object" for reference:
myServices.factory('Object', ['$resource',
function($resource){
return $resource('object/:id', {id: '#id'}, {
update: {method: 'PUT'},
});
}
]);
I had the exact same problem. I used an interceptor in the resource definition to inject the http headers in the resource.
$resource('/api/resource/:id', {
id: '#id'
}, {
index: {
method: 'GET',
isArray: true,
interceptor: {
response: function(response) {
response.resource.$httpHeaders = response.headers;
return response.resource;
}
}
}});
Then, in the then callback, the http headers are accesible through $httpHeaders:
promise.then(function(resource) {
resource.$httpHeaders('header-name');
});
I think I had a similar problem: After POSTing a new resource I needed to get the Location header of the response, since the Id of the new resource was set on the server and then returned via this header.
I solved this problem by introducing my own promise like this:
app.factory('Rating', ['$resource',
function ($resource) {
// Use the $resource service to declare a restful client -- restangular might be a better alternative
var Rating = $resource('http://localhost:8080/courserater/rest/ratings-cors/:id', {id: '#id'}, {
'update': { method: 'PUT'}
});
return Rating;
}]);
function RestController($scope, $q, Rating) {
var rating = new Rating();
var defer = $q.defer(); // introduce a promise that will be resolved in the success callback
rating.$save(function(data, headers){ // perform a POST
// The response of the POST contains the url of the newly created resource
var newId = headers('Location').split('/').pop();
defer.resolve(newId)
});
return defer.promise;
})
.then (function(newId) {
// Load the newly created resource
return Rating.get({id: newId}).$promise; // perform GET
})
.then(function(rating){
// update the newly created resource
rating.score = 55;
return rating.$update(); // perform PUT
});
}
We can't use .then for returning the header because the promise doesn't allow for multiple return values. (e.g., (res, err))
This was a requested feature, and was closed https://github.com/angular/angular.js/issues/11056
... the then "callbacks" can have only [one] argument. The reason for this is that those "callbacks" correspond to the return value / exception from synchronous programming and you can't return multiple results / throw multiple exceptions from a regular function.

Restangular: getList with object containing embedded array

In my AngularJS project I'm trying to use the Restangular getList method but it's returning an error because the API response is not directly an array but an object containing an array.
{
"body": [
// array elements here
],
"paging": null,
"error": null
}
The Restangular error message is:
Error: Response for getList SHOULD be an array and not an object or something else
Is it possible to tell Restangular that the array it's looking for is inside the body property?
Yes, see the Restangular documentation. You can configure Restangular like so:
rc.setResponseExtractor(function(response, operation) {
if (operation === 'getList') {
var newResponse = response.body;
newResponse.paging = response.paging;
newResponse.error = response.error;
return newResponse;
}
return response;
});
Edit: It seems Restangular's API is now changed, for the better, and that the current method to use is addResponseInterceptor. Some adjustments might be needed to the function passed.
I think you should use a the customGET from the Custom Methods
Restangular.all("url").customGET(""); // GET /url and handle the response as an Object
as Collin Allen suggested you can use addResponseInterceptor like this:
app.config(function(RestangularProvider) {
// add a response intereceptor
RestangularProvider.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
var extractedData;
// .. to look for getList operations
if (operation === "getList") {
// .. and handle the data and meta data
extractedData = data.body;
extractedData.error = data.error;
extractedData.paging = data.paging;
} else {
extractedData = data.data;
}
return extractedData;
});
});

$resource $delete won't remove Resource object

I have an AngularJS $resource:
App.factory("pjApi", ["$resource", function($resource) {
return $resource("/api/:user/:action/:post_id/", {action:"posts"});
}]);
and in my controller, I basically use it like this:
$scope.deletePost = function(post_id) {
$scope.posts.forEach(function(post) {
if (post_id === post.id)
post.$delete({user:"tjb1982",action:"delete",post_id:post.id});
});
}
The server gives a response with status 200, application/json, and body: "1"
What Angular does with this response is to remove the deleted instance of the Resource object, but then Angular replaces it with the response from the server (i.e. "1"), as if I were creating or updating:
posts
[Resource { 0="1", $$hashKey="00D", $get=function(), more...}]
etc.
So my template is updated with this new (mostly blank) information, which is what I'm trying to avoid. I've tried returning nothing from the server or "0"-- returning nothing results in the Resource instance being preserved entirely and returning "0" results in the same as returning "1".
What response is Angular looking for in order for this Resource instance to be removed entirely so that my template renders correctly?
Calling $delete on a resource only sends the HTTP request to the server; if you want to remove the item from some client side representation--such as an array--you must do so yourself.
So, for your example, you might try something like the following:
$scope.deletePost = function(post_id) {
$scope.posts.forEach(function(post, index) {
if (post_id === post.id) {
post.$delete({user:"tjb1982",action:"delete",post_id:post.id}, function() {
$scope.posts.splice(index, 1);
});
}
});
}
// instance is cleared on success
post.$delete({/* request data */}, function() {
// remove empty element from array
$scope.posts = $scope.posts.filter(function(el) {
return el.id !== undefined;
});
});

Resources