How to define a path section in custom actions of $resource? - angularjs

Is it possible to specify the path of a custom $resource action ?
I would like to write something like:
angular.module('MyServices', [ 'ngResource' ]).factory('User', [ '$resource', ($resource)->
$resource('/users', {}, {
names: { path: '/names', method: 'GET', isArray: true }
})
])
So I can use it like:
User.names() # GET /users/names

It is not directly supported in the current version of AngularJS but there is a pull request open so there is chance that it will be supported in the near future.
Till then you've got 3 options:
1) Play with variables in the path:
$resource('/users/:names', {}, {
names: { params: {names: 'names'}, method: 'GET', isArray: true }
})
2) Use the $http service instead
3) Try the code from the mentioned PR on the monkey-patched version of AngularJS

Check the logs in this working Plunker (excerpt):
var app = angular.module('plunker', ['ngResource'])
.controller('MyController',
function($scope, $resource) {
var User = $resource(
'/users/:action',
{},
{
names:{
method:'GET',
params:{action:'names'}
}
}
);
$scope.users = User.get();
$scope.names = User.names();
}
);

A less eloquent, but equally effective method:
var resourceUrl = '/users';
return $resource(resourceUrl, {}, {
names: { path: resourceUrl + '/names', method: 'GET', isArray: true }
})

From Angular documentation: https://docs.angularjs.org/api/ngResource/service/$resource
you can specify 'url' for your custom action which will override the previous one.
angular.module('MyServices', ['ngResource']).factory('User', ['$resource', ($resource)-> $resource('/users', {}, {
names: { url: '/users/names', method: 'GET', isArray: true }
})])
It works in my project using angular 1.3.10!

Related

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)

Service for YouTube oEmbed

I'm trying to create a Service in Angularjs to make use of various oEmbed providers including YouTube.
...
myServices.factory('YouTubeService', function ($resource) {
//how can I make the URL part dynamic?
return $resource('http://www.youtube.com/oembed/', {}, {
query: { method: 'GET', isArray: true },
})
});
...
The oEmbed URL structure is http://www.youtube.com/oembed?url=<url_of_video>
How can I make this service work with any YouTube URL provided by the user? In other words, can I call this Service from my Controller and pass in the URL in some way?
YouTubeService.query(<url here maybe>)
Here you go, this should work, I think.
myServices.factory('YouTubeService', function ($resource) {
var youtubeservice = {};
youtubeservice.query = function(urlProvided){
return $resource('http://www.youtube.com/oembed?url=:urlProvided', {}, {
query: { method: 'GET', isArray: true },
});
}
return youtubeservice;
});
Invoke:
YouTubeService.query(<url here>)
I am not sure if you can access external url like this(may throw cross domain error)
But for your question, why don't you use a service instead of factory like this
myServices.service('YouTubeService', function ($resource) {
//how can I make the URL part dynamic?
this.getStuff = function(url){
return $resource(url, {}, {
query: { method: 'GET', isArray: true },
}).query();
}
});
And invoke it like
YouTubeService.getStuff (dynamicUrl);

No data returned in consuming REStful web service using Angularjs

I am beginner learning Angularjs .Please help me with examples for following
script added
javascript -
var app = angular.module('myapp', []);
app.controller('MyCtrl1', ['$scope', 'UserFactory', function ($scope, UserFactory) {
UserFactory.get({}, function (userFactory) {
$scope.time = userFactory.time;
})
}]);
var service = angular.module('apiService', ['ngResource']);
service.factory('UserFactory', function ($resource) {
return $resource('http://time.jsontest.com', {}, {
query: {
method: 'GET',
params: {},
isArray: true
}
})
});
.html file
<body ng-app="myapp">
<divng-controller="MyCtrl1" >
<p>
Result from RESTful service is: {{ time }}
</p>
</div>
</body>
above snippet gives the out put as
Result from RESTful service is : {{time}}
and not the value i am expecting
..Reference : http://draptik.github.io/blog/2013/07/13/angularjs-example-using-a-java-restful-web-service/
I want to write CRUD methods (GET/POST/PUT/DELETE) and I have started with GET.
Thanks
You need to make sure that your main app module injects your service. In your plnkr you have:
var app = angular.module('myapp', []);
where you should really have:
var app = angular.module('myapp', ['apiService']);
This ensures that the service module is injected into your app module, and you can use the UserFactory that you define in that module. For this simple case you could have also simply defined the UserFactory factory on the 'myapp' module as well
It's very close but you have a slight mistake in your app instantiation. It should be the following:
var app = angular.module('myapp', [ 'apiService' ]);
There's a couple other issues I see as well but one thing is I usually do the following for async requests
var promise = UserFactory.get({}).$promise;
promise
.then( function(response) {
$scope.time = userFactory.time;
});
EDIT: Here's an example for named methods for a given ReST service:
return $resource('/api/v2.0/user/lists/:listId',
{},
{
// POST - list create/product addition to list
'addProduct': {
method: 'POST',
isArray: false,
params: {
listId: '#listId',
productId: '#productId'
}
},
'createList': {
method: 'POST',
isArray: false,
params: {
listName: '#listName'
}
},
// GET - list of user lists/list details
'readLists': {
method: 'GET',
isArray: false,
params: {}
},
'readListsWithProductId': {
method: 'GET',
isArray: false,
params: {
productId: '#productId'
}
},
'readListById': {
method: 'GET',
isArray: false,
params: {
listId: '#listId',
sort: '#sort',
flags: true,
extendedInfo: true,
rows: '#rows',
start: '#start'
}
},
// PUT - list renaming
'renameList': {
method: 'PUT',
isArray: false,
params: {
newName: '#listName',
listId: '#listId'
}
},
// DELETE - list deletion/clear/product removal
'removeProduct': {
method: 'DELETE',
isArray: false,
params: {
listId: '#listId',
productId: '#productId'
}
},
'clearList': {
method: 'DELETE',
isArray: false,
params: {
listId: '#listId',
clear: true
}
},
'deleteList': {
method: 'DELETE',
isArray: false,
params: {
listId: '#listId'
}
}
});
You could access it like the following:
Factory.[methodName](payload)

Angularjs: a Service that serves multiple $resource urls / data sources?

I have an Angular service/provider that serves json data to my controller which works great:
angular.module('myApp.services', ['ngResource']).
factory("statesProvider", function($resource){
return $resource('../data/states.json', {}, {
query: {method: 'GET', params: {}, isArray: false}
});
});
But I also need to serve json data to the same controller from another file counties.json.
Where can I find out how to I write a service that serves both files to my controller?
You can update service to return a hash of resources, not a single one:
angular.module('myApp.services', ['ngResource']).
factory("geoProvider", function($resource) {
return {
states: $resource('../data/states.json', {}, {
query: { method: 'GET', params: {}, isArray: false }
}),
countries: $resource('../data/countries.json', {}, {
query: { method: 'GET', params: {}, isArray: false }
})
};
});
You will be able to use it adding .query() at the end your function name i.e. geoProvider.states.query() and geoProvider.countries.query() and myApp.services has to be injected into your controller, then inject geoProvider service into controller itself as well.
I'm assuming you want to execute some code when both files have loaded. Promises work really well for this. I don't think resources return promises, but you can use the $http service for simple ajax calls.
Here I define one service each for the two data files, and a third service that returns a promise that gets fulfilled when both files are done loading.
factory('states',function($http) {
return $http.get('../data/states.json');
}).
factory('countries',function($http) {
return $http.get('../data/countries.json');
}).
factory('statesAndCountries', function($q, states, countries) {
return $q.all([states, countries]);
});
Then in your controller:
statesAndCountries.then(function(data) {
var stateData = data[0];
var countryData = data[1];
// do stuff with stateData and countryData here
});

AngularJS - $resource different URL for Get and Post

$resource is awesome providing very convenient way to handle web services.
What if GET and POST have to be performed on different URLs?
For example, GET URL is http://localhost/pleaseGethere/:id
and POST URL is http://localhost/pleasePosthere without any parameter
Use 'url' property of [actions] to override the default url.
$resource(url, [paramDefaults], [actions], options);
for example:
$resource('http://localhost/pleaseGethere/:id',{},{
getMethod:{
method:'GET',
isArray:true
}
postMethod:{
url:'http://localhost/pleasePosthere',
method:'POST',
isArray:false
}
}
Usage of Angular $resource: http://docs.angularjs.org/api/ngResource/service/$resource
You should be able to expose the URL as a parameter. I was able to do this:
$provide.factory('twitterResource', [
'$resource',
function($resource) {
return $resource(
'https://:url/:action',
{
url: 'search.twitter.com',
action: 'search.json',
q: '#ThingsYouSayToYourBestFriend',
callback: 'JSON_CALLBACK'
},
{
get: {
method: 'JSONP'
}
}
);
}
]);
Then you can overwrite the URL on your GET call.
The one caveat I found during my REALLY brief testing was that if I included http:// in the URL string, it didn't work. I didn't get an error message. It just did nothing.
If you add the hash with param names into the $resource call:
$resource('localhost/pleaseGethere/:id', {id: '#id'});
Then the :id will be mapped to id param when invoking the function (this will call GET localhost/pleaseGethere/123):
Resource.get({id: 123});
For POST, you simply don't assign the id param:
Resource.post({}, {name: "Joe"});
The proper URL will be called, which is in this case POST localhost/pleaseGethere (the trailing slash is stripped by ngResource).
See http://docs.angularjs.org/api/ngResource.$resource -> Examples -> Credit card resource for more details.
In addition to Iris Wong's answer, I wanted to give an example of having multiple params with multiple methods and actions:
angular
.module('thingApp')
.factory('ThingResource', ['$resource', '$state', returnThing]);
And the resource:
function returnThing($resource, $state) {
var mainUrl = '/api/stuffs/:stuffId/thing'
var params = {stuffId: '#_id', thingMongoId: '#_id', thingNumber: '#_id'}
return $resource(mainUrl, params, {
'save': {
url: '/api/stuffs/:stuffId/thing/:thingMongoId',
method: 'POST',
interceptor: {
responseError: function(e) {
console.warn('Problem making request to backend: ', e)
$state.go('oops')
}
}
},
'get': {
url: '/api/stuffs/:stuffId/thing/:thingMongoId',
method: 'GET',
interceptor: {
responseError: function(e) {
console.warn('Problem making request to backend: ', e)
$state.go('oops')
}
}
},
'assignThing':{
method: 'POST',
url: '/api/stuffs/:stuffId/thing/assign/:thingNumber'
}
});
}
Which gives 3 separate methods:
// POST to http://currnt_base_url/api/stuffs/:stuffId/thing/:thingMongoId
ThingResource.save({
stuffId:'56c3d1c47fe68be29e0f7652',
thingMongoId: '56c3d1c47fe6agwbe29e0f11111'})
// GET to current http://currnt_base_url/api/stuffs/:stuffId/thing/:thingMongoId
ThingResource.get({
stuffId:'56c3d1c47fe68be29e0f7652',
thingMongoId: '56c3d1c47fe6agwbe29e0f11111'})
// POST to http://currnt_base_url/api/stuffs/:stuffId/thing/assign/:thingNumber
ThingResource.assignThing({
stuffId:'56c3d1c47fe68be29e0f7652',
thingNumber: '999998'})
Follow this way:
(function () {
'use strict';
angular
.module("app")
.factory("SomeFactory", SomeFactory);
function SomeFactory($resource) {
var provider = "http://stackoverflow.com/:action/:id";
var params = {"id":"#id"};
var actions = {
"create": {"method": "POST", "params": {"action": "CreateAwesomePost"}},
"read": {"method": "POST", "params": {"action": "ReadSomethingInteresting"}},
"update": {"method": "POST", "params": {"action": "UpdateSomePost"}},
"delete": {"method": "GET", "params": {"action": "DeleteJustForFun"}}
};
return $resource(provider, params, actions);
}
})();
I hope it help! Enjoy!

Resources