my service has to use a query string due to limitations on the server that runs classic ASP:
angular
.module('myServices', ['ng', 'ngResource'])
.factory('Item', ['$resource',
function ($resource) {
return $resource('/api/?p=item/:id');
}]);
and I want to add extra query string parameters to it:
Item.query({test: 123}, on_success, on_error);
but the resulting url is
/api/?p=item?test=123
apparently there is a bug, but how to get around it?
EDIT: filed this at https://github.com/angular/angular.js/issues/1511
You can use resource parameters. If you haven't specified placeholders in the path, they would automatically be converted into query string params. Like that:
angular
.module('myServices', ['ng', 'ngResource'])
.factory('Item', [
'$resource',
function ($resource) {
return $resource('/api');
}]);
Item.query({p: 'item/1'});
This would result in a request to /api?p=item/1.
P.S.
I suppose you already know that, but you don't like it. But I still think this is the correct way in your case. Considering the bad API design you are dealing with that back-end you could wrap the AngularJS resources with another service which does this for you.
var deferred = $q.defer();
api.api_name.query({
'param':param_value
},
function(response) {
deferred.resolve(response);
},
function(response) {
deferred.reject(response);
}
);
//
angular
.module('module_name')
.factory('api',function($resource){
var api_var={};
api_var.api_name = $resource('url?param_key=:param', {
param: '#param'
}, {
'query': {
method: 'get'
}
});
return api_var;
});
Related
I am trying to make a POST request via $resource object in Angular.
I have something like
(function (angular) {
angular.module('myApp')
.factory('myService', [
'$resource',
function ($resource) {
var serviceObj = $resource('http://testProject/products/', {id: '#id'},{
'createItem' : {
url: 'http://testProject/item/:id',
method: 'POST',
params: {type: ‘#type'}
}
});
return serviceObj;
}
]);
})(angular);
in my controller
//omit the controller codes…
myService.type = ‘Detail’;
myService.createItem(function(data) {
console.log(data)
});
I see stuff back from the console.log but it has the wrong data because the type is shown as ‘Name’ instead of ‘Detail’. I know api supports that and I don’t see anything wrong with my service. Can someone help me out for it? Thanks a lot!
It looks like your are getting data back,
I would try:
console.log(data.data);
Since your are returning an object from your service.
I am learning about the MEAN stack, and have created a REST API which posts a review to a collection in MongoDB.
I have defined a service as given:
angular.module('myApp')
.constant('baseURL', 'http://localhost:8080/');
angular.module('myApp')
.service('addReviews', ['$resource', 'baseURL', function($resource, baseURL) {
this.getReviews = function() {
return $resource(baseURL+'reviews/', null, {'save': {method: 'POST'}});
};
}]);
Now, I am calling this service from my controller:
angular.module('myApp', ['ngResource'])
.controller('reviewController', ['$scope', 'addReviews', function($scope, addReviews) {
$scope.reviewSubmit = function() {
$scope.receivedReviews = false;
var review = {
// some data
};
$scope.reviews = addReviews.getReviews().query(
function(response) {
$scope.reviews = response;
$scope.receivedReviews = true;
},
function(response) {
$scope.reviews = response;
// print error message
}
);
console.log($scope.reviews); // showing empty array
};
}]);
In routes.js, I have configured my route as:
var Reviews = require('./models/reviews');
...
app.post('/reviews', function(req, res) {
Reviews.create(req.body, function(err, post) {
if (err) {
return res.send(err);
}
return res.json(post);
});
});
I am trying to post a new review to the Reviews collection. However, $scope.reviews is showing an empty array. I logged the requests, and it shows a GET request is being to /reviews instead of POST. I think I should use save() instead of query(), but I have seen some tutorials online where they used query() despite the method being PUT/POST in the service. I am really confused. Can anyone point out how I can post the data (in var review) to the Reviews collection?
There are some issues with your code on the angular side of things.
You want to use $resource as an all-purpose object to communicate with the API. It has built-in functionality to:
query: get all resources from a given API endpoint
get: a single resource, usually by specifying that resource's id
save: post, with an object sent across in the body of the request. NOTE: you don't need the {'save': {method: 'POST'}} in your $resource configuration, you get it for free.
remove and delete: self-explanatory
So you'd want to set up your reviews factory (incl. url constant) like:
angular.module('myApp', ['ngResource'])
.constant('baseURL', 'http://localhost:8080/')
.factory('Reviews', ['$resource', 'baseURL', function($resource, baseURL) {
return $resource(baseURL+'reviews/:id', {id: '#id'});
}]);
If you want to have access to all saved reviews in your controller, as $scope.reviews, you'd do something like:
angular.module('myApp')
.controller('reviewController', ['$scope', 'Reviews', function($scope, Reviews) {
// hit API endpoint to get all reviews
// will have to have app.get('/reviews', function(req, res) {...})
// configured in your node code
Reviews.query(function(data) {
$scope.reviews = data;
}, function(error) {
console.log(error);
});
// and if you want to take a user-written review, say $scope.userReview,
// from the view and save it to the database on click function submitReview()...
$scope.userReview = {
message: '',
createdTime: null
};
// ^ not sure what your ReviewSchema looks like on the backend, but for example...
$scope.submitReview = function() {
if ($scope.userReview.message.length) {
$scope.userReview.createdTime = Date.now();
Reviews.save($scope.userReview);
// ^ this will make POST request with the $scope.userReview object as the request body
}
};
}]);
The create method on your back end looks fine. The object (or maybe just string) you send across will have to match your review schema. You may want to log the request body to make sure you're getting what you expect.
Have a look at this short post on using $resource to interact with RESTful APIs, and (the slightly more confusing) angular $resource docs, for more information on the $resource service.
Hope this helps you!
I swear this was working before I upgraded ngResource to 1.3.11...
So my issue is that when I apply a custom filter param to my odata resource request, the filter appends an extra $ before it write the parameter.
http://myservice/odata/Data?&format=application%2Fjson&$filter=year(Date)+lt+2012
The above works just fine through fiddler and is the correct request.
I'm using ngResource to make the get request
data.factory('DataService', ['$resource', function ($resource) {
var odataUrl = 'http://myservice/odata/Data?&format=application%2Fjson';
var d = $resource('', {
filter: '#filter'
}, {
queryByYear: {
method: 'GET',
url: odataUrl, isArray: false
}
});
return d;
}]);
and controller function is as follows:
$scope.getByYear = function (op) {
DataService.queryByYear({ filter: 'year(PublishedDate) ' + op }, function (data) {
$scope.events = data;
});
};
For some reason the output of this request is as follows:
http://myservice/odata/Data?&format=application%2Fjson&$$filter=year(Date)+lt+2012
Notice the second and completely unnecessary & beside the filter param...
any thoughts?
After looking into what was happening when converting my odata request to the proper format, I realized that I had added a third party angular-odata module that was preforming the conversion. The newer angularjs $http already handles this conversion. Doh!
I'm trying to grab a single result from my expressjs api from within my AngularJS factory.
The factory looks like this and grabs all posts from my api(written in expressjs and getting data from mongodb), which is working fine:
angular.module('bonsaiService', ['ngResource']).
factory('bonsaiService', function($q,$resource) {
var bonsaiResource = $resource('http://localhost:8888/api/bonsais/:bonsaiId',{},{
get:{
method: 'GET',
params:{bonsaiId:''},
isArray: true
}
});
return {
get:function(){
var q = $q.defer();
bonsaiResource.get({
},
function(resp){
q.resolve(resp);
},function(httpResponse){
q.reject(httpResponse);
});
return q.promise;
}
//find by id
};
});
What i've tried so far is adding :bonsaiId after the $resource url and adding params for that id like this: params:{bonsaiId: ''}.
The server part (expressJS) look like this:
router.route('/bonsais/:bonsaiId')
.get(function(req,res){
Bonsai.findOne(req.params.bonsaiId,function(err,bonsai){
if(err)
res.send(err);
res.json(bonsai)
})
})
When I call a local url (with and existing _id from mongodb) it works fine and returns my data in json :
http://localhost:8888/api/bonsais/536be2e2ae54668818000001
Now in the controller im trying to get this data in my scope, which is not working.
bonsaiService.get({bonsaiId:$routeParams.bonsaiId}).then(
function(data){
$scope.trees = data;
console.log(data);
});
How do I make this work?
You could use a more simple approach here.
The query method for $resource already defines a GET on an array, which is QUERY.
Why not write your service this way :
.factory('bonsaiService', ['$resource',
function($resource) {
return $resource('http://localhost:8888/api/bonsais/:bonsaiId', {
bonsaiId: '#bonsaiId'
});
}
])
And in your controller, it would work like this :
bonsaiService.query({
bonsaiId: $routeParams.bonsaiId
}, function success() {
//Your code
}, function err() {
//Your code
});
Don't forget to inject the service in the controller or the app file, if it's not done already.
I'm trying to pick up angular.js and working on figuring out some of the things that are a bit less documented.
Consider this - I have a search method on the server that accepts query params and returns a collection of search results, and responds to GET /search.json route (Rails FWIW).
So with jQuery, a sample query would look like this:
$.getJSON('/search', { q: "javascript", limit: 10 }, function(resp) {
// resp is an array of objects: [ { ... }, { ... }, ... ]
});
I'm trying implement this using angular, and wrap my head around how it works. This is what I have now:
var app = angular.module('searchApp', ['ngResource']);
app.controller('SearchController', ['$scope', '$resource', function($scope, $resource){
$scope.search = function() {
var Search = $resource('/search.json');
Search.query({ q: "javascript", limit: 10 }, function(resp){
// I expected resp be the same as before, i.e
// an array of Resource objects: [ { ... }, { ... }, ... ]
});
}
}]);
And in the view:
<body ng-app="searchApp">
...
<div ng-controller="SearchController">
...
<form ng-submit="search()">...</form>
...
</div>
</body>
However, I keep getting errors like TypeError: Object #<Resource> has no method 'push' and $apply already in progress.
Things seem to work out as expected if I change the $resource initialization to the following:
var Search = $resource("/search.json?" + $.param({ q: "javascript", limit: 10 }));
Search.query(function(resp){ ... });
It seems more intuitive to initialize the $resource once and then pass different query parameters with changes in the requested search. I wonder if I'm doing it wrong (most likely) or just misunderstood the docs that calling $resource.query with the query params object as the first argument is feasible. thanks.
TypeError: Object # has no method 'push' and $apply already
in progress
because you have not defined a resources with the name Search. First you need to define such a resource. Doc: $resource. Here is an example implementation
angular.module('MyService', ['ngResource'])
.factory('MyResource', ['$resource', function($resource){
var MyResource = $resource('/api/:action/:query',{
query:'#query'
}, {
search: {
method: 'GET',
params: {
action: "search",
query: '#query'
}
}
});
return MyResource;
}]);
Include this module in you app and use it in a controller like this
$scope.search_results = MyResource.search({
query: 'foobar'
}, function(result){});
However I am not sure if this is what you need. The resource service interacts with RESTful server-side data sources aka REST API.
Maybe you need just a simple http get:
$http({method: 'GET', url: '/someUrl'}).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
http://docs.angularjs.org/api/ng.$http