AngularJS transformResponse - angularjs

In angularjs resource, I would like to convert my json data into JS objects
//Complex object with inheritance chain
function Car(year, make){
this.make = make;
this.year = year;
}
var carResource = $resource("/api/car/id", {id: '#id'},
{
get: {
method: 'GET',
transformResponse: function(data, headersGetter){
return new Car(data.make, data.year);
}
}
}
)
However this does not seem to be happening
What I am getting back is a $resource object meaning that the properties make and year are set correctly, however the prototype of the returned object points to $resource
Is there a way where I can map my json data directly to my own objects?
Or will I have to write my own 'resource' implementation?

transformResponse is executed on $http level.
When you customise $resource actions with custom config object, that object is actually passed on to the underlying $http service. So if you specify a transformResponse callback, it will be executed on $http level, and the results of your transformation will be passed back on to $resource.
$resource service will instantiate new object from your response data (which is already transformed by the transformResponse callback) and this new object will be an instance of the $resource itself.
So, your car object will be an instance of the Car, but only for a moment, until it's properties are copied into a new $resource object.
Here's a simplistic view of the process:
$resource service initiates request
$http service sends request and receives the response
$http service transforms the response (response is now instance of Car)
$resource service receives the transformed response (from $http)
$resource service makes an instance of itself using transformed response properties (result is now instance of $resource)
Anyway, I don't recommend decorating or extending the $resource service, because it's simpler to write your own implementation using $http service.

Related

How to get boolean value using $resource of AngularJS and spring rest controller

Trying to send get boolean value from spring restcontroller using $resource service of angular js ,but getting nothing in response of $resource.get.Is there anythingextra i need to add on my client side or server side for getting boolean resource. Below is my code for rest controller and $resource
Rest controller -
#RequestMapping(value="validate/company/{companyName}",method=RequestMethod.GET,produces={"application/json"})
public Boolean validateCouponCode(#PathVariable("companyName") String companyName){
return companyService.exists(companyName, Column.SITE_NAME);
}
$resourse of Angular js -
function validateCompanyFn(companyName)
return $resource("admin/rest/company/validate/company/:companyName")
.get({companyName:companyName}).$promise
}
What i am doing wrong?
please suggest, if there is another way of getting boolean response using $resource, and without using any extra object on server side
$resource does not return booleans
The $resource.get method only returns object references, not booleans.
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data.
Under the hood, the $resource service uses angular.copy to populate the object.
angular.copy
Creates a deep copy of source, which should be an object or an array.
If a destination is provided, all of its elements (for arrays) or properties (for objects) are deleted and then all elements/properties from the source are copied to it.
— AngularJS angular.copy API Reference
Since a boolean has no elements/properties, nothing is copied.
To return a boolean, use the $http service:
//USE $http service
function getSubCategoryIdNameFn(catId){
var url = "admin/rest/subcategory-id-name/" + catId;
return $http.get(url).then(function(response) {
return response.data;
});
};
There is no need to manufacture a promise with $q.defer as $promise already is a promise. Simply return the $promise
//SIMPLIFY
function getSubCategoryIdNameFn(catId){
//var deferred = $q.defer();
//vvvv RETURN the $promise
return $resource("admin/rest/subcategory-id-name/:catId",{catId:"#catId"})
.query({catId:catId})
.$promise
//.then(function(response){
// deferred.resolve(response);
//},function(error){
// deferred.reject(error);
//});
//return deferred.promise;
}

JHipster : when to use $http and when to use $resource

I'm exploring how jhipster manipulates data. I have found $http.get() in getProfileInfo method in ProfileService Service whitch interacting restful api :
function getProfileInfo() {
if (!angular.isDefined(dataPromise)) {
dataPromise = $http.get('api/profile-info').then(function(result) {
if (result.data.activeProfiles) {
var response = {};
response.activeProfiles = result.data.activeProfiles;
response.ribbonEnv = result.data.ribbonEnv;
response.inProduction = result.data.activeProfiles.indexOf("prod") !== -1;
response.swaggerDisabled = result.data.activeProfiles.indexOf("no-swagger") !== -1;
return response;
}
});
}
return dataPromise;
}
and some where i have found $resouce() manipulating GET method. for example in BankAccount factory :
var resourceUrl = 'api/bank-accounts/:id';
I searched for when to use $http and when to use $resource and i found this :
AngularJS $http and $resource
why hipster is not following consistent way of interacting API and manipulating data!!?
so jhipster, when to use $http and when to use $resource in services??
We use $resource when requesting a RESTful endpoint, for example for an entity. $resource provides basic REST operations easily whereas $http is more specific.
For profile we only need to GET /profile-infos so it's useless to use $resource because we'll never need to call POST or DELETE on that URL.
$http will fetch you the entire page or complete set of data from a given URL whereas $resouce uses http but will help you to fetch a specific object or set of data.
$resource is fast and we use it when we need to increase the speed of our transaction.
$http is used when we are concerned with the time.

ngResource transformResponse doesn't seem to be transforming the response

I made a base class, HttpService:
class HttpService
constructor: (url) ->
#service = $resource url, {}, #actionOptions()
actionOptions: ->
query:
method: 'GET'
isArray: true
transformResponse: (data) =>
response = []
wrapped = angular.fromJson(data)
angular.forEach wrapped[#indexRoot], (item) =>
response.push #jsonToModel(item)
response
I inherit like this:
class FooService extends HttpService
constructor: ->
super '/api/foos/:id'
#indexRoot = 'foos'
all: ->
#service.query()
jsonToModel: (data) ->
new Foo(data)
In general, the idea is to extend HttpService providing the URL of the resource and the index root (JSON has a root element for the index action). I override jsonToModel to provide a way to transform each JSON element in the response into a custom object, in this case Foo.
When debugging, I can see that response is what it should be in actionOptions(), so it seems like transformResponse is returning what I expect, an array of Foos.
Whenever I call FooService.all() though, I get an array of Resources (ngResource default)... anyone have any idea what I'm doing wrong? I've omitted the dependency injection and everything, but it's all working and I have no errors in console.
The $resource service wraps the response in Resource objects using an interceptor, which occurs after the transformResponse, so while transformResponse is a good place to unwrap a root object (the results from there get fed into the interceptors), you will also need an interceptor to call your jsonToModel function.
The relevant docs:
https://docs.angularjs.org/api/ngResource/service/$resource
transformResponse – {function(data, headersGetter)|Array.} – transform function or an array of such functions. The transform function takes the http response body and headers and returns its transformed (typically deserialized) version. By default, transformResponse will contain one function that checks if the response looks like a JSON string and deserializes it using angular.fromJson. To prevent this behavior, set transformResponse to an empty array: transformResponse: []
interceptor - {Object=} - The interceptor object has two optional methods - response and responseError. Both response and responseError interceptors get called with http response object. See $http interceptors.

Is it OK to fake a promise on a new angular resource?

I'm working with $resource in Angular 1.3.
I have a bunch of controllers with methods that work with the resource objects.
When the state of retrieval matters, these methods use the $promise property of the resource to ensure that they only process the objects after they are retrieved. These all work fine with existing and updated resource objects.
var ProposalResource = $resource(proposalUrl, {id: '#id'}, {'update': {method: 'PUT'}});
The resource objects are obtained by ProposalResource.get({id:....
However, when I create a new resource object in order to make a new object using new ProposalResource(..., the methods fail because the $promise property is undefined.
I've worked around this by setting the $promise property on the new resource object to a resolved promise.
This seems to work OK but it feels like a nasty kludge. The option of explicitly checking for whether or not the $promise property is defined in all the other methods is even less appealing though.
Am I doing the right thing?
I don't know why you need to use ProposalResource, but I usually use the $q provider.
That way you can do a simple function that returns a promise and you can call it from your controller methods.
Example service that uses a promise:
function someServiceMethod(params) {
//do something here, maybe create an object,maybe make a call with $http or something
var obj = createSomeObject(params);
//this resolves the object once the createSomeObject method or function have completed
$q.when(obj);
}
This approach is easier than doing the whole: var deferred = $q.defer(); and return deferred.promise after the deferred.resolves.
If you're using $resource, then I recommend just using $http provider from angular.
Here's $http
Here's $q
As mentioned in the $resource AngularJS Doucmentation:
Class actions return empty instance (with additional properties
below). Instance actions return promise of the action.
The statement above gives you a hint that instance action methods, $get, $save, ... and any other actions that you define in your $resource action definition, will always return a promise.
DEMO
e.g.
var User = $resource('user.json', {}, {
'update': {'method': 'PUT'}
});
var user = new User();
// this sends a GET request to user.json and returns the promise directly
// from the instance action.
user.$get()
.then(function(latestUserData) {
// latestUserData is also an instance of the User resource
return latestUserData.$update({
'name': 'Ryan'
});
})
.then(function(updatedUserData) {
// do whatever you want here
});
As you can see, the instance action $get returns a promise and when that promise is resolved, the .then() callback returns the response data from the server and at the same time it is wrapped/instantiated with the User $resource.

Is it suitable to use $httpBackend in production to abstract data service requests?

I have a data service in my application that is responsible for retrieving information for my controllers. This information might come from local storage, window or an ajax request. The problem I am facing is the $q promise responses don't look like $http responses.
this.getContactDetails = function(data) {
// The first time this method is called, we expect contact details to be preloaded on the page.
// We want to read and return that object then remove it from the page so subsequent requests are to the server.
if(typeof $window.preloadData.contact !== 'undefined') {
var contactDetails = JSON.parse(JSON.stringify($window.preloadData.contact));
delete $window.preloadData.contact;
// Since the method call should always have the same return type, we manually create a deferred object and set the resolution using the $q service.
var deferred = $q.defer();
deferred.resolve(contactDetails);
return deferred.promise;
}
var request = requests.contactDetails.get;
return $http(request);
};
The $q service does a nice job here but it resolves as the object it was given. I wouldn't really expect it to wrap the response. I know $httpBackend could accomplish this.
$httpBackend.whenGET(request).respond(contactDetails);
But the service is used in the MockE2E library and I doubt this was its intended use. I am not sure how to call this off afterwards or what would happen if I used it twice on the same request but I can figure out these questions. My other concern is that there doesn't seem to be a way to pass the same config object to $httpBackend as I do to $http. $httpBackend only accepts a method, url, body and headers, while $http config allows me to specify parameters.
Currently my work-around is simply to create and $http-like wrapper myself.
var contactDetails = JSON.parse(JSON.stringify({
data: $window.preloadData.contact
}));
But I don't find this very elegant. Is there a better/correct way to do this?
You can implement your storage layer as a $cacheFactory and add it to $httpProvider during the configuration phase.
From the docs:
When the cache is enabled, $http stores the response from the server in the specified cache. The next time the same request is made, the response is served from the cache without sending a request to the server.
Hence, if you provide your own implementation of a cache with the following methods:
{object} info() — Returns id, size, and options of cache.
{{*}} put({string} key, {*} value) — Puts a new key-value pair into the cache and returns it.
{{*}} get({string} key) — Returns cached value for key or undefined for cache miss.
{void} remove({string} key) — Removes a key-value pair from the cache.
{void} removeAll() — Removes all cached values.
{void} destroy() — Removes references to this cache from $cacheFactory.
You can return values read from localStorage, session cookies, etc. and they will be treated as there were data sent from the server, just without the AJAX request.

Resources