i have a factory in my app:
dashboard.factory('ProxyStatusFactory', ['$resource','CodisData', function ($resource,CodisData) {
return $resource('http://' + CodisData.Addr + '/api/proxy', {}, {
query:{ method: 'GET', url : 'http://' + CodisData.Addr + '/api/proxy/list', isArray: true },
setStatus:{ method: 'POST' }
});
}]);
the CodisData is a angular value
dashboard.value("CodisData",{"Name":"NA","Addr":"NA"});
then i use it in my controller like this:
$scope.codis_name = selected.Tag;
$scope.codis_addr = selected.Addr;
CodisData.Addr = selected.Addr;
$scope.proxy_array = ProxyStatusFactory.query();
i changed CodisData.Addr ,but in ProxyStatusFactory ,$resource also return 'http://na/api/proxy'
so when CodisData change,how synchronized update ProxyStatusFactory and return correct $resource?
try this:
dashboard.factory('ProxyStatusFactory', ['$resource', function ($resource) {
return $resource('http://:addr/api/proxy/', {}, {
query: {
method: 'GET',
url: 'http://:addr/api/proxy/list',
params: {},
isArray: true
},
setStatus:{ method: 'POST' }
});
}]);
then use in controller like this:
ProxyStatusFactory.query({addr: CodisData.Addr});
Moving forward with explanation...
angular factory/service are singletons, so they are created only ONCE. So http url is also created only once, based on current value of CodisData.Addr.
Thats why + CodisData.Addr + is changed to :addr to make this part of url configurable....
I hope this helps :)
#update
tested on local project and injecting variables into url part, works as expected, but when desired url is external rest api then it fails with message you describe.
In that case You can dynamically create $resource object. Here is jsfiddle with working factory that creates resources dynamically.
https://jsfiddle.net/qwetty/mxrz2cxh/13/
Related
I am using angular resource in order to retrieve a record from my AP.
Below is my relevant controller information.
$scope.formInformation = formService.get({id:$state.params.form_id });
Below is my service
(function(){
"use strict";
angular
.module("mainAppModule")
.factory("formService", formService);
function formService($resource)
{
return $resource(apiLink + 'form/:id',
//{id: '#_id'}, //this breaks it
{
'query' : {
method: 'GET',
isArray: true,
}
},
{
'get' : {
method: 'GET',
url: apiLink + 'form/individualForm/:id',
}
}
);
}
})();
When I try to overwrite the url variable, it still uses the original one which is.
"apiLink +"form/:id"
as opposed to
apiLink + 'form/individualForm/:id',
which should be overwritten by the following line.
url: apiLink + 'form/individualForm/:id',
but when I remove.
{id:'#id'},
My url is overwritten.
I am trying to understand why that is the case.
I am using angular and angular resource version 1.7.7.
The actions parameter is malformed:
function formService($resource)
{
return $resource(apiLink + 'form/:id',
//{id: '#_id'}, //this breaks it
{
'query' : {
method: 'GET',
isArray: true,
}
̶ ̶}̶,̶
̶{̶
'get' : {
method: 'GET',
url: apiLink + 'form/individualForm/:id',
}
}
);
}
The actions parameter should be a hash of all the resource actions. When the actions were spread over two objects, only the first object overrode the default. The action declaration for get was ignored and the default was used.
I've got a problem with service configuration. I want to display one user by this function:
$scope.findOne = function() {
$scope.user = Users.get({
userId: $stateParams.userId
});
};
But I am in trouble with User service :( I don't know, how should I change my the code to avoid angular error:
Error in resource configuration for action object. Expected response
to contain an array but got an {2}
Here is a code of my actual working service (without function findOne working of course:))
'use strict';
angular.module('users').factory('Users', ['$resource',
function($resource) {
return $resource('users', {}, {
update: {
method: 'PUT'
},
remove: {
method: 'DELETE',
url: 'users/:id',
params: {id: '#_id'}
}
});
}
]);
At a guess, I'd say your users API endpoint is expecting /users/:userId for GET requests. Your code at the moment will request /users?userId=nnn. You need to add an action for get with the ID in the URL, eg
return $resource('users', {id: '#userId'}, {
get: {
method: 'GET',
url: 'users/:id',
isArray: false
},
// etc
You can also make users/:id the default URL as long as it doesn't interfere with your other action configurations.
I have a custom resource defined as such:
app.factory('SpaceGroupService', ['$resource', function ($resource) {
return $resource('api/SpaceGroup/:id', { id: '#id'},
{
'parkingSpaces': { method: 'GET', url: 'api/SpaceGroup/:id/ParkingSpaces', isArray: true }
});
}]);
The idea is to pass in an ID of my space group object to return all parking spaces in that group. When I call
SpaceGroupService.query()
While running on my local iisexpress it's hitting the correct service url:
/api/SpaceGroup
But when I do:
spaceGroup.$parkingSpaces({ id: spaceGroup.SpaceGroupId }, function (parkingSpaces) {
spaceGroup.parkingSpaces = parkingSpaces;
});
It is querying my restful service as:
/api/SpaceGroup/2
instead of:
/api/SpaceGroup/2/ParkingSpaces
I'm somewhat new to angularJS and I know my route works on my API controller so I'm just trying to get this service to work properly. Any ideas why this overwritten URL isn't called?
I'd would write your service like this instead:
app.factory('SpaceGroupService', ['$resource', function ($resource) {
return
{
ParkingSpaces: $resource('api/SpaceGroup/:id/ParkingSpaces', {},
{
query: { method: 'GET', params: { id: '#id'}, isArray: true }
}
}
}]);
And then call it like this instead:
SpaceGroupService.ParkingSpaces.query({ id: someId });
You can set up multiple resources in the service this way - and you can define multiple methods too (GET, POST, PUT, DELETE). It also means that Angular will honor your $resource url.
In my code I have:
var EntityResource = $resource('/api/:entityType', {}, {
postEntity: { url: '/api/:entityType/', method: 'POST' },
getEntity: { url: '/api/:entityType/:entityId', method: 'GET' },
putEntity: { url: '/api/:entityType/:entityId', method: 'PUT' },
deleteEntity: { url: '/api/:entityType/:entityId', method: "DELETE" },
getEntities: { url: '/api/:entityType/:action/:id', method: 'GET', isArray: true },
});
Then I am using the following to get data:
getProjects: function (
entityType,
deptId) {
var deferred = $q.defer();
EntityResource.getEntities({
action: "GetProjects",
entityType: entityType,
deptId: deptId
},
function (resp) {
deferred.resolve(resp);
}
);
return deferred.promise;
},
and the following to call getProjects:
entityService.getProjects(
'Project',
$scope.option.selectedDept)
.then(function (result) {
$scope.grid.data = result;
}, function (result) {
$scope.grid.data = null;
});
I think the intermediate function getProjects is not needed and I would like to directly use $resource.
Can someone give me some advice on how I could do this? I looked at the AngularJS documentation for $resource and it's not very clear for me.
$resource calls by default return empty arrays and then fill them up when the response is received. As mentioned in documentation
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.
There are default 5 methods already defined on resource, get,save,query,remove,delete. You can directly call these rather than defining your own as you have done like postEntity, but the url template remains the same.
So once you define resource like this
var entityResource = $resource('/api/:entityType');
you can make calls like
var entity=entityResource.get({entityType:1},function(data) {
//The entity would be filled now
});
See the User example in documentation
If you want to return promise then you have to wrap the calls into your your service calls like you did for getProjects.
Update: Based on your comment, the definition could be
var entityResource = $resource('/api/:entityType/:action/:id')
Now if you do
entityResource.get({},function(){}) // The query is to /api
entityResource.get({entityType:'et'},function(){}) // The query is to /api/et
entityResource.get({entityType:'et',:action:'a'},function(){}) // The query is to /api/et/a
entityResource.get({entityType:'et',:action:'a',id:1},function(){}) // The query is to /api/et/a/1
Hope it helps.
$resource does expose $promise but it is on return values and subsequent calls.
My rest api accpets DELETE requests to the following url
/api/users/{slug}
So by sending delete to a specified user (slug) the user would be deleted. here is the service code:
angular.module('UserService',['ngResource']).factory('User', function($resource){
var User = $resource('/api/users/:id1/:action/:id2', //add param to the url
{},
{
delete_user: {
method: 'DELETE',
params: {
id1:"#id"
}
},
update: {
method: 'PUT',
params: {
id1:"#id"
}
}
});
return User;
});
I call the delete function via
user.$delete_user({id:user.id}, function(){}, function(response){});
However the request seems to be send to the wrong url.
/api/users?id=4
So the parameter is actually missing, as a result I get a 405 Method not allowed. Is there any chance to send the delete request in the style of my api?
params is an object of default request parameteres in your actions. If you want url parameters you have to specify them in the second parameter like this:
angular.module('UserService',['ngResource']).factory('User', function($resource){
var User = $resource('/api/users/:id1/:action/:id2', //add param to the url
{id1:'#id'},
{
delete_user: {
method: 'DELETE'
}
});
return User;
});
this works with either:
// user has id
user.$delete_user(function(){
//success
},function(){
// error
});
or
var data = {id:'id_from_data'};
User.delete_user({},data);
or
var params = {id1:'id1_from_params'};
User.delete_user(params);
I've made a plnkr-example - you have to open your console to verify that the DELETE requests are correct.
See parameterDefaults in the Angular resource documentation.
I had this problem for a while I was using a service to add / delete / update categories. While passing in params for get it worked fine but then when deleting it was giving me a ?id=1234 instead of api/resource/1234
I got around this by making the default param a string.
///Controller
Service.delete({categoryId:id}, function(resp){
console.log(resp)//whatever logic you want in here
});
//SERVICES
$resource('api/resource/:categoryId', {"categoryId":"#categoryId"}, {
query:{method:"GET"},
delete:{method:"DELETE"},
});
Should work and the resulting url will be, originally I had categoryId in the default params as a variable name.
api/resource/1234 etc
Just omit the '#' in the parameter
.factory('reportFactory', ['$resource', 'baseUrl', function ($resource, baseUrl) {
return $resource(baseUrl + '/keys/:id', {}, {
delete: { method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
params: {id: 'id'} }
})
}]);
this will give you:
http://localhost:8080/reports/api/keys/b8a8a8e39a8f55da94fdbe6c
without the question mark
If you want to delete a model, there's no need to add params (params does not work for DELETE anyway):
$resource('/users/:id').delete({id: user.id}, function(res) {
...
})
or
$resource('/users/:role/:id').delete({role: 'visitor', id: user.id});
I'm not sure if it's a bug of ngResource.