How to update angular resource urls with id from the authenticated user? - angularjs

So I have defined multiple angular factories with ngResource similar to:
.factory('factoryName', ['$resource', '$http', 'CONSTANTS', 'authService', factoryNameCtrl])
function factoryNameCtrl($resource, $http, CONSTANTS, authService) {
var actions = {
'get': {
method: 'GET',
isArray: false,
params: {
service: '#service',
action: '#action'
}
},
'post': {
method: 'POST',
isArray: false,
params: {
service: '#service',
action: '#action'
}
}
}
actions.get.params.userId = actions.post.params.userId = '#' + authService.currentUser.id;
var res = $resource(CONSTANTS.baseURL + '/:userId/integrations/:service/:action', {}, actions);
If I log in and logout with another user, the value of userId inside the factory doesn't update.
I don't want to pass userId into each params from all over my code, but to make it available when it changes.
Previously I had the code below and I was forcing a page reload to rebuild the correct urls into the resource.
if (authService.isAuthenticated()) {
var res = $resource(CONSTANTS.baseURL + '/' + authService.currentUser.id + '/integrations/:service/:action', {}, actions);
return res;
}
What do you advise to do?

To compute it fresh every time, use a function:
actions.get.params.userId = function () {
return computeCurrentUserId();
};
From the Docs:
If a parameter value is a function, it will be executed every time when a param value needs to be obtained for a request (unless the param was overridden).
-- AngularJS $resource API Reference

Related

Setting a factory variable in controller in angularjs

I need to set a factory variable in my controller. This variable is used for the url for returning a save function in my factory. I actually build this url as several pieces but this is a simplified version.
myApp.factory('SaveDate', ['$resource',
function saveDateFactory($resource, $http) {
var myData = '';
return $resource(myData, {}, {
query: { method: "POST", params: {}, isArray: false },
});
}]);
The function from my controller looks like this:
vm.myFunction1 = function ($resource) {
vm.myDate = '/test/MyProduct/SetSalesDate/988093099/108/2016/05/21';
SaveDate.myData = vm.myDate;
//this should save the date for milestones
SaveDate.query();
vm.cleanUp();
};
I have tried using an object instead of a primitive but it also didn't work. I have tested and my value for SaveDate.myData is being set accurately. If I hard code a value in the spot where I declare my variable in the factory, it will save perfectly. I am just not able to pass the variable successfully from my controller to my factory. I have tried a wide variety of ways to do this including using $watch. Thanks for your help on this!
When I added a function like this:
myApp.factory('SaveDate', ['$resource',
function saveDateFactory($resource, $http) {
var myData = {};
myData.getMyUrl = function (urlStuff) {
alert("in SaveDate" + urlStuff);
return $http.get(urlStuff);
}
return $resource(myData.getMyUrl, {}, {
query: { method: "POST", params: {}, isArray: false }
Adding this function throws the following error: Unknown provider: myDataProvider <- myData <- UserListController
You'll need to create a function in your factory as Clint said in the comments.
myApp.factory('SaveDate', ['$resource',
function saveDateFactory($resource, $http) {
var myData = '';
function setMyData(data) {
myData = data;
}
return {
setMyData: setMyData,
resource: $resource(myData, {}, {
query: { method: "POST", params: {}, isArray: false },
})
};
}]);
In your controller:
SaveDate.setMyData(vm.myDate);

AngularJS Request payload is always empty

I have created a Angular resource that sends POST data to a web service. Here is my factory:
appServices.factory('Foo', function($resource) {
var data = $resource(
'http://localhost:3000/api/v1/foo.json',
{},
{
'save': {
method: 'POST',
cache: false
}
});
return data;
});
Here's my Controller:
appControllers.controller('FooCtrl', function($scope, Foo, $location) {
$scope.memberData = {};
$scope.create = function() {
var member = new Foo();
member.$save( {}, { bar: bar });
$location.url("/");
};
});
When I submit the form in my client, it returns a 500 status. Looking into Firebug, I can see that my POST data payload always remains empty for some reason.
What am I doing wrong?
PS. I've added this to my config: $httpProvider.defaults.headers.post['Content-Type'] = 'application/json; charset=utf-8';
If you want to issue a POST request to the member resource, you can use save() (without the $) and pass in your body as the first argument:
Foo.save({bar: 'bar'}, function () {
// Callback
});
However, when creating a new resource instance, it is augmented with a $save() method (note the $). When you invoke this method, the instance itself is sent as the body. So you should change your code to:
var member = new Foo();
member['bar'] = 'bar';
member.$save(function () {
// Callback
});
Check this article for more information.

Allowing variable length arguments to Angular's $resource?

Here's the issue, I have multiple API calls to make along the lines of:
www.domain.com/foo/bar?token=12345
There may be more subdirectories in-between, there may be less.
I'm currently using $resource
agentApp.factory('apiFactory', function($resource) {
return $resource('www.domain.com/v1/' + ':folder',
{
'query': {
method: 'GET',
isArray: true
}
});
Which gets called as follows:
apiFactory.query({folder: 'foo', token: '12345'}, function() {...})
I would like to make this more extensible as I have the need to occasionally change the isArray value to false, and the amount of subdirectories in the URL are unknown on occasion, so I'd prefer to not use $resource's :token structure, and rather just have one that takes a string.
Is there a service I could create that would allow me to make the call as follows:
apiService.query(urlStringAndQueries, booleanForIsArray).then(function(response) { ...do something with response });
So far I've attempted the following, which obviously doesn't give me what I want, I'm not sure how to get $resource to actually kick off the API call, I put this down to a fundamental misunderstanding of how $resource works:
agentApp.factory('apiService', ['$resource', '$q', function ($resource, $q) {
var factory = {
query: function (urlStringAndQueries, isArray) {
return $q(
function() {
$resource('www.domain.com/v1/' + ':location', { location: urlStringAndQueries }, {
'query': {
method: 'GET',
isArray: isArray
}
});
}
)
},
return factory;
}]);
Which I attempt to call as follows:
apiService.query('/foo/bar?token=12345', true)
.then(function(response) { ...do something with response });
Any help and/or advice is very much appreciated.
Thanks!
EDIT: Here's my solution until a more generic pattern comes along
I couldn't simply provide an extra entity to the base URL string externally, e.g. foo/bar?token=12345, due to $response inherently encoding URL, so the characters (/?=) get converted into their encoded counterparts. Hence the separating of strings in the pattern:
agentApp.factory('apiService', ['$resource', function($resource) {
var factory = {
resourceObj: function(isArray, urlStringAndQueries) {
/* urlStringAndQueries will be variadic parameters,
so we deconstruct them for use in the URL */
var location1, location2, location3, locations = [];
angular.forEach(arguments, function(path) {
locations.push(path);
});
return $resource(vapiURL + vapiVer + '/' + ':location1' + '/' + ':location2' + '/' + ':location3' + '/' + ':location4', {
location1: locations[1],
location2: locations[2],
location3: locations[3],
location4: locations[4],
}, {
'query': {
method: 'GET',
isArray: isArray
},
'save': {
method: 'POST',
isArray: isArray
}
})
}
};
return factory;
}]);
This solution still assumes I'll have a finite amount of paths, which isn't ideal but at least it's easy to reuse.
Still open to more and better suggestions :)
I don't understand why you are returning promise object from your service method again, while $resource return promise itself. Don't do that
Code
agentApp.factory('apiService', ['$resource', '$q', function($resource, $q) {
var factory = {
resourceObj: function(urlStringAndQueries, isArray) {
return $resource('www.domain.com/v1/' + ':location', {
location: urlStringAndQueries
}, {
'query': {
method: 'GET',
isArray: isArray
}
});
)
}
}]);
Call factory method then you'll get access to resource object then call its query of that resource object method
Controller
apiService.resourceObj('/foo/bar?token=12345', true).query()
.then(function(response) { ...do something with response });

POST to nested RESTful resources with $resource parameter mismatch - AngularJS

I'm trying to using the $resource library of angular, to POST data to a nested resource.
My following nested resource of event looks like so
events/:eventId/match - POST
events/:eventId/match - GET
events/:eventId/match/:matchId - GET
I set up a service with angular
app.factory('EventService', ['$resource', function ($resource) {
var Event = $resource('/events/:eventId', {eventId: '#id'},
{
createMatches: {
url: '/events/:eventId/match',
method: 'POST'
}
);
return {
createMatches: function(data,event_id) {
var data.eventId = event_id;
return Event.createMatches(data).$promise;
}
}
});
Controller where it has been called:
app.controller('EventController', ['$scope','EventService', function($scope,EventService) {
$scope.create = function(event_id,title,description) {
EventService.createMatches({
title:title,
description: description
},event_id).then(function(result) {
console.log('event_created', result);
})
}
}]);
Problem
When I send the request to the server I expect the url that looks like so: /events/10/match
But instead the resource doesn't add the eventId as a parameter of the url but add it as a parameter of the request, for this reason my call fail because the url looks like so: /events/match.
I can't understand why it doesn't bind the :eventId to the url. Any suggest will be appreciated.
I believe that you are missing your second parameter decalaration, as per this link for the actions you are defining:
app.factory('EventService', ['$resource', function ($resource) {
var Event = $resource('/events/:eventId', {eventId: '#id'},
{
createMatches: {
url: '/events/:eventId/match',
method: 'POST',
params: {eventId: '#id'}
}
);
return {
createMatches: function(data,event_id) {
var data.eventId = event_id;
return Event.createMatches(data).$promise;
}
}
});

Angular $resource not working correctly

I am trying to build my first Angular $resource to give my application access to CRUD operations, but for some reason the actions being configured for the resource are not defined when I try to execute a query.
Here is my controller logic:
app.controller('MainCtrl', function ($scope, $http, $resource) {
var Alert = $resource('/WebApi/Alert/:type/:id',
{
systemUpdate: { method: 'GET' },
autoArchive: { method: 'POST', url: '/WebApi/Alert/Template/:type' }
});
$scope.systemUpdate = function (alert) {
var data = Alert.systemUpdate({ type: alert.Status, id: alert.AlertId }); // THIS LINE FAILS
console.log(data);
}
I get an error saying that Alert.systemUpdate is not defined. Am I doing something wrong here when configuring my $resource?
Change the definition of your Alert to
var Alert = $resource('/WebApi/Alert/:type/:id',
{},
{
systemUpdate: { method: 'GET' },
autoArchive: { method: 'POST', url: '/WebApi/Alert/Template/:type' }
});
As mentionned in the documentation of $resource, the order of the parameters is the following:
1) Url
2) The default value of the parameters of the url, since you don't have any default value, you must provide an empty object
3) The actions (systemUpdate & autoArchive here)

Resources