AngularJS: POSTing something new with $resource - angularjs

I'm having trouble using $resource to POST something new... It works great for updates & queries, but when I try and create a new 'article', its getting a little confusing.
Basically my POST should be sent to "/articles/". The ID of the article is set through the form on the front end, however when I submit the POST it is sent to "/articles/ARTICLE_ID"(ARTICLE_ID being replaced with whatever I set on the form).
Here is my article service:
angular.module('testapp.articles')
.factory("Articles", ['$resource', function($resource) {
return $resource('articles/:articleId', {
articleId: '#articleId'
}, {
update: {
method: 'PUT'
}
});
}]);
This is my controller:
$scope.create = function() {
var article = new Articles({
articleId: this.articleId
});
article.$save(function(response){
console.log(response);
});
};
Any help is appreciated, thanks!

It goes off to /articles/ARTICLE_ID because that is what you specified while creating the Article. You do not need to supply article_id as a parameter.
$scope.create = function() {
var article = new Articles();
article.articleId = this.articleId
article.$save();
...
};
With the newer versions of AngularJS, articleId will be picked up anyway. Your service could be simplified as follows:
angular.module('testapp.articles')
.factory("Articles", ['$resource', function($resource) {
return $resource('articles/:articleId', null,
{
'update': { method: 'PUT' }
});
}]);
AngularJS $resource

Related

Unable to create POST request to REST API with $resource in angularjs

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!

Unable to use $update, $remove and $save in ngresource

I am using ngresource as follows but unfortunately I am unable to access the $update, $remove and $save methods in this way. What am I doing wrong?
angular.module('myApp.services').factory('Entry', function($resource) {
return {
method1: $resource('/api/entries/:id', { id: '#_id' }, {
update: {
method: 'PUT' // this method issues a PUT request
}
}),
method2: $resource('/api/entries2', {}, {
})
});
// not working: Entries is not a function at Scope.$scope.save
var entry = new Entries({});
entry.method1.$update();
entry.method1.$save();
entry.method1.$delete();
On the other hand, this works:
angular.module('myApp.services').factory('Entry', function($resource) {
return $resource('/api/entries/:id', { id: '#_id' }, {
update: {
method: 'PUT' // this method issues a PUT request
}
});
});
var entry = new Entries({});
entry.$update();
entry.$save();
entry.$delete();
So your second example doing $resource('http://example.com/resource.json') is the correct usage of that construction, while the first one is not.
After executing var entry = new Entries({}); you get entry as factory instance in your controller, which has available actions that you've defined for it.
UPD
You can have multiple resources in the service - https://stackoverflow.com/a/17163459/405623. In your example you've just missed the ['ngResource'] DI in your module.

How to use Angular Query resource

I'm using MEAN.JS 0.4 and I need some help with Angular Resource.
My problem is this:
I want to make this API and be able to filter data server side, but I dont know how to use this Query method.
I want to do something like this:
Products.query({
stock: 0
}, function(result){
console.log(result)
});
This is my actual Angular service:
//Discounts service used for communicating with the discounts REST endpoints
angular.module('discounts').factory('Discounts', ['$resource',
function ($resource) {
return $resource('api/discounts/:discountId', {
discountId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
]);
Discounts.query({stock: 0}).$promise
.then(function(data) {
products = data; })
or
products = Discount.query({stock: 0}, function() {
//do something whith products
});

Getting a single result with angularjs factory in MEAN stack

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.

angular js getting data from laravel and print it

Hi I'am trying a simple example of using a controller and a factory to get some data back to the view but for some reason I can't print it.
I managed to get the ajax call to work.
If I type the
$scope.sampleStyles = [{ sample: 'text here', text : 'dasdas'}
and don't use the ajax call it works
UPDATE: if I add an alert before assigning to my scope it works (ajax has time to do his thing)
anyone know how to overcome that?
CODE:
var packageApp = angular.module("packageApp", []);
packageApp.controller("MyController", function($scope, myFactory){
$scope.sampleStyles = [];
function init(){
$scope.sampleStyles = myFactory.getSampleStyles();
}
init();
});
packageApp.factory('myFactory', function($http, $log){
var factory = {};
var sampleStyles = [];
var tempData = {};
factory.update = function(){
$.ajax({
type: 'POST',
url: '/account/fetch-sample-styles',
data: {
source: 'ajax'
},
success: function(data, textStatus, XMLHttpRequest){
tempData = data;
}
});
alert(tempData);
sampleStyles = tempData;
}
factory.getSampleStyles = function(){
factory.update();
return sampleStyles;
};
return factory;
});
Are you using the AngularJs $http service? If so it will return a promise which you then operate on. Here is more on promises from the AngularJs docs.
My guess is, you are using an ajax.get(...) with a success callback defined inside. The problem is probably due to the success callback not belonging to the "AngularJs world."
To fix this, you need to tell AngularJs that its scope has changed. Use the $[Root]scope.$apply() function, and have the scope injected into your service as a dependency.
Something like this inside the factory:
$.ajax({
url: "/api/some/end/:point",
...
success: function(data) {
$scope.$apply(function() {
$scope.sampleStyles = data; // etc
});
}
});
I strongly recommend that you look into the $http service, it makes the above code much nicer, and is designed to play nice with the $scope.
$http.get("/api/end/point").then(function(response) {
// response.data points at the page data sent back, assuming that your
// api endpoint sends back JSON of the likes of
// { status: "SUCCESS", styles: [...] }
$scope.sampleStyles = response.data.styles;
});
EDIT:
Now that you posted some code, it seems like the root of your issue is based on the fact that the ajax get is an async call. Why are you even messing with using a temporary variable? Why not the following?
factory.update = function(){
$.ajax({
type: 'POST',
url: '/account/fetch-sample-styles',
data: {
source: 'ajax'
},
success: function(data, textStatus, XMLHttpRequest){
sampleStyles = data;
}
});
}
If you really wanted to make the $.ajax call blocking, you can set async: false in the $.ajax properties.
EDIT 2:
Fixed some broken links, sorry I am a SO newb :(

Resources