Angular js nested resource - angularjs

I want to configure an angular $resource. This $resource should allows to call distant web services.
// Gets all the nested-resources of a parent-resource
1) GET /parent-resource/nested-resources
// Gets a nested-resource by id
2) GET /nested-resource/{id}
// Create a nested resource
3) POST /nested-resource
In my scenario, i want retrieve all the nested resources using the first web service. When a nested resource is modified by the user, the nested resource will be save using the third web service.
var NestedResource = $resource('/nested-resource/:id');
Publishable.prototype.isNew = function() {
return this.id === undefined;
};
... lot of functions...
This configuration works well to hit the 2nd and 3rd web services but how can i configure the resource to use the 1st. Several functions are register on the nested resource prototype, i would like to avoid the creation of a specific $resource.
Publishable.prototype.getByParentId = function(parentId) {
// ??
}

Create a custom action on the resource as follows:
var NestedResource = $resource('/nested-resource/:id',,
{ action: "getAll",
method: "GET",
isArray: true,
url: '/parent-resource/:parentId/nested-resources'
});
Now you should be able to do:
var allItems = NestedResource.getAll({parentId: 1});
to retrieve the list for parentId 1.

Related

How to contact a non-standard API using Angular ngResource

The API I am using requires a non-standard where clause if I try to search for a particular non-id field. The endpoint I need is:
http://127.0.0.1:4001/api/testusers/findOne?userName=Anton
So this will find me the first record in the testusers table whose column (userName) = 'Anton'.
My standard service is:
angular.
module('shared.testUser').
factory('TestUser', ['$resource',
function($resource) {
return $resource('http://127.0.0.1:4001/api/testusers/:id', {id:'#id'},//parameters
{
update: {
method: 'PUT' // To send the HTTP Put request when calling this custom update method.
}
});
}
]);
and my calling function is:
self.checkUsersEntryDirection = function(){ //NOT WORKING
self.testuser = TestUser.get({ username: 'anton' }, function() {
console.log(angular.toJson(self.testuser));
}); // get() returns a single entry
}
Clearly this doesn't work and I can't use the standard get approach. Can anyone think how this can be achieved?
You could create a secondary factory TestUserByName, and make the following changes:
angular.
module('shared.testUser').
factory('TestUserByName', ['$resource',
function($resource) {
return $resource('http://127.0.0.1:4001/api/testusers/findOne?userName:username', null,
{
update: {
method: 'PUT' // To send the HTTP Put request when calling this custom update method.
}
});
}
]);
Call the get action method with two parameters:
var params = {id: "findOne", username: "anton"};
self.checkUsersEntryDirection = function(){
self.testuser = TestUser.get(params, function() {
console.log(angular.toJson(self.testuser));
}); // get() returns a single entry
}
The id parameter will override the default and username parameter will be added as a query string.
From the DOCS:
Each key value in the parameter object is first bound to url template if present and then any excess keys are appended to the url search query after the ?.
Given a template /path/:verb and parameter {verb:'greet', salutation:'Hello'} results in URL /path/greet?salutation=Hello.
--AngularJS ngResource $resource Service API Reference

Sending Array of Objects to Web API from AngualrJS

During this process, I grab an array of "vehicles" from the Web API. I modify and do whatever to each vehicle. Then I want to send the list back, without going through and looping...
I've tried a lot of the ways that i've looked up.
I've got this in the WEB API for a breakpoint to see if I can even get the array there, but I havent been able to yet.
public IHttpActionResult UpdateVehicles(Vehicle[] vehiclesArry)
{
return Ok();
}
I'm confused if I need to do a $post, or if I could just "get" it to the correct method like I've been doing. The problem is I can't get the array to the WEB API method.
I've got my $resource setup like this.
return $resource(appSettings.serverPath + "/api/Violators/:id",null,
{
'update': { method: 'PUT' },
'delete': { method: 'DELETE' },
'post': { method: 'POST' }
});
I've tried using $post, but it says the object doesn't support it. I'm not sure what other ways I can try. I've tried using "dynamic" in the web API, that doesn't seem to work either.
You're missing the params object for $resource, so it doesn't know the id.
return $resource(appSettings.serverPath + "/api/Violators/:id", { id: '#id' });
You don't need to explicitly setup methods for get, post, delete. That's already done for you. If your API uses PUT for update, set that up like this:
return $resource(appSettings.serverPath + "/api/Violators/:id", { id: '#id' }, {
update: { method: 'PUT' }
});
Also, the property on your resource must be vehiclesArry exactly or web API won't know how to map it. I also want to echo #sowen. You will need to setup a view model that your endpoint receives.
My assumption is that you are having some script errors in your page or you are not using the $http methods properly.
One problem people usually run into is using the correct url to the web api endpoints in your angular controller. If you don't get it right, you might be getting 404 errors. Look for those in your browser console(network tab)
The below code should work fine without any issues
$http.get("../api/Values/")
.then(function (res) {
var vehicles = res.data;
console.log('data received', JSON.stringify(vehicles));
//Let's update the Name of each vehicle.
$.each(vehicles, function (indx, item) {
item.Name = item.Name + " Updated";
});
console.log('data modified', JSON.stringify(vehicles));
//Let's make a call to web api with modified data
$http.post("../api/Values/UpdateVehicles", vehicles)
.then(function (res2) {
console.log('response', JSON.stringify(res2.data));
});
});
Assuming you have angular js properly loaded in your page and the above code is part of your angular controller for the current page and you have the Web api controller with 2 action methods like below example.
public class ValuesController : ApiController
{
[HttpPost]
[Route("api/Values/UpdateVehicles")]
public IHttpActionResult UpdateVehicles(Vehicle[] vehiclesArry)
{
// just returning whatever came in for TESTING PURPOSE
return Ok(vehiclesArry);
}
public IEnumerable<Vehicle> Get()
{
return new List<Vehicle>
{
new Vehicle {Id = 1, Name = "Car"},
new Vehicle {Id = 2, Name = "Van"}
};
}
}
Also,FYI : I am using Attribute routing in my api controller for the UpdateVehicle endpoint.
Create a model object like
public class UpdateReq
{
public IEnumerable<Vehicle> Vehicles { get; set; }
}
From your angular, just pass a json with an array
{
[v1, v2, v3]
}

AngularJs $resource, REST and Symfony2 FOSRestBundle

I am using the FOSRestBundle, this bundle generates routes for me and pluralises those routes. For instance a GET request to /users.json is different from a GET request to /user/15.json
Its worth noting that a call to /users/15.json fails.
More on this issue here https://github.com/FriendsOfSymfony/FOSRestBundle/issues/247
In my Angular app I use a $resource to create a RESTful call, the URL is a template as detailed here https://docs.angularjs.org/api/ngResource/service/$resource
For example
$resource('http://example.com/:id.json')
Or
$resource('http://example.com/user/:id.json')
And there in is the problem, the $resource seems to accept a single URL template for the REST resource, but I have multiple ones because of the forced pluralisation from the FOSRestBundle.
I do not think hacking the FOSRestBundle is the answer, so what can I do with my usage of $resource in AngularJs to correct this issue?
you can set url for every method as third parameter - actions
angular.module("example", ["ngResource"])
.factory("userService", function($resource) {
return $resource("http://example.com/user/:id.json", {
id: "#id"
}, {
'query': {
url: "http://example.com/users"
}
})
})
.run(function(userService) {
userService.query();
userService.get({id:1});
})

Capture server JSON response in end-to-end test

I'm writing an end-to-end test that simulates user authentication with Protractor. A user feels in her credentials and clicks a Submit button. As a result, the server returns an access token in a JSON response that can be used for other REST API calls. I'd like to save this token to a file.
There's a similar question on capturing a response of a GET request here, but I'm not sure it's a good idea to send another request after I click the button.
How can I capture the response after a button click?
Here is my idea about how to catch HTTP responses. Protractor provides a method browser.addMockModule() (docs) - it is used to add custom Angular modules to a page, which are usually used to mock outcoming requests and provide custom response. But we do not need to mock requests, it would be enough to just listen for whatever comes from a server. It can be achieved with the help of Angular HTTP interceptors. Interceptors are used to catch a request or a response and modify it for whatever needs before in gets to it's endpoint. We can use them to collect information about what is coming from the server, store it, and then let response go forward without changes. Since this custom module and spec tests will run on the same page, information about responses can be stored in some global property. Then, when button is clicked, it would be possible to inject custom script to a page to retrieve required responses via browser.executeScript() (docs). Here is the source:
it('should intercept requests', function () {
// Inject custom Angular module on a page
// Script should be injected before you "browser.get()" the page
browser.addMockModule('e2eHttp', function () {
// Note: This function scope is not a Protractor environment
angular
.module('e2eHttp', [])
.config(function ($httpProvider) {
// add custom interceptor to all requests
$httpProvider.interceptors.push('e2eHttpInterceptor');
})
.factory('e2eHttpInterceptor', function () {
return {
response: function (response) {
// name of the global property to store responses
var global = 'e2eHttpResponses';
// responses will be grouped by url
// but you can use data from "response.config" to adapt it
// it has a lot of info about response headers, method, etc
var url = response.config.url;
window[global] = window[global] || {};
window[global][url] = window[global][url] || [];
window[global][url].push(response); // store response
// proceed without changing response
return response;
}
};
});
});
// Load the page
browser.get('#/auth/login');
$('#submit').click();
// If we are sure that response has come, then extract it
browser.executeScript(function () {
// Note: This function scope is not a Protractor environment
var global = 'e2eHttpResponses';
var uri = 'api/auth/login.json';
// extract array of stored responses for required uri
var responses = (window[global] && window[global][uri]) || [];
// return responses to spec
return responses;
}).then(function (responses) {
// and finally, we are now able to get all information we need
// about response, and in your case, save it to a file
console.log(responses);
var data = responses[0].data; // first response body as a string
});
// remove injected module not to break another specs
browser.removeMockModule('e2eHttp');
});
You can move setup and injection calls to some utility modules, so test specs would be clean.

Define Service or factory using ngResource to retrieve data from server side?

I'm developing angular web app. And I have this controller which needs to call restful api to do some operations on Users.
Earlier I'm thinking define a service which has some methods: getAllUser( ), getUser(id), saveUser( ), deleteUser( ). these methods will use a ngResource to call rest apis.
But when I look at these methods, it seems to me that I'm just wrapping the ngResource and expose some of his lower level methods: query( ), get( ), save( ), delete( ).
Could someone share some experience about how will you design common services or factories or providers which use ngResource to fetch data from server?
I've been working on an angular project myself. And I'd built a Factory manually, and then ended up using JBoss Forge for my second attempt and that build stuff for me in a pretty nice way, here's what it looked like:
angular.module('myApp').factory('myResource', function($resource){
var urlBase = '/rest/resources';
var resource = $resource(urlBase + '/:RsvpId',{RsvpId:'#id'},{'queryAll':{method:'GET',isArray:true},'query':{method:'GET',isArray:false},'update':{method:'PUT'}});
return resource;
});
That's all there is to it, then when you want to call it, you do something like the following:
$scope.save = function() {
var successCallback = function(data,responseHeaders){
var id = locationParser(responseHeaders);
$location.path('/Resources/edit/' + id);
$scope.status = 'success';
};
var errorCallback = function(data, status, headers, config) {
$scope.status = 'failure';
$scope.statusMessage = 'Saving your resource failed: ' + $scope.errorMessage;
};
myResource.save($scope.resource, successCallback, errorCallback);
};
or to do a get, you'd have this line inside a method:
myResource.get({ResourceId:$routeParams.ResourceId}, successCallback, errorCallback);
or
resource.$remove(successCallback, errorCallback);
Hope that helps.
Let me explain about ngResource...
ngResource is a service from AngularJs and it use at lower lever the $http service, so its very simple to use it when you want to use the RESTFul Resources. Here is my example:
myAppModule.factory('User', ['$resource', function($resource) {
return $resource('/user/:userId'}
]);
So what this code above are doing? This is creating a service that return a resource, the url was mapped, so when you inject and call this service you receive a object with some methods: "GET", "POST", "PUT", "DELETE"... Example:
var users = User.query();
The variable "users", receive all users(and plus it receive some resource features like save, because "users" variable still being a resource object), it's like you make this request (.../user/), ok? All you have to do is call resource, it's very simple.

Resources