WORK AROUND IS AT THE BOTTOM
Original problem
There are question like this all over the web and none of them really have answer for me. I can't get an http PATCH operation to work using angular to save my life. I've implemented $http, with shortcut $http.patch and without using the config object method:PATCH. I've used $resource by adding a custom method. And I've implemented Restangular using their patch and I'm getting the same error. I have the correct Content-Type as suggested in other posts. I think it's safe to say at this point, it's something I'm missing. I'm getting the same "404" message via postman when trying to patch. I can PUT, GET, POST, and DELETE, but not PATCH.
In the following images you can see that the resource exists for GET. But when trying to patch I get 404. Browsing to that endpoint shows the record. Which is stored in Mongodb.
Here's some code snippets:
Resangular GET:
var corporiumRecord = Restangular.one('corporium-mgmnts', $scope.uuid);
corporiumRecord.get().then(function(res) {
console.log(res)
}, function(err) {
console.log('Restangular failed: ', err)
});
Restangular Patch:
var data = {
corporiumId: $scope.newBlock
};
var corporiumRecord = Restangular.one('corporium-mgmnts', $scope.uuid);
corporiumRecord.patch(data).then(function(res) {
console.log(res)
}, function(err) {
console.log('Restangular failed: ', err)
});
$http attempt using config object:
controller code:
httpCorporiumSrv.updateCorporiumId('/corporium-mgmnts/' + $scope.params.id, data)
.then(handleUpdateSuccess)
.catch(handleUpdateError);
service code, tried forcing the content-type header but got same result
with or without it:
function updateCorporiumId(url, data) {
return $http({
method: 'PATCH',
url: url,
data: angular.toJson(data),
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
//transformRequest: transformUpdateData
})
.then(handleUpdateSuccess)
.catch(handleUpdateErrors);
}
Using the .patch shortcut:
function updateCorporiumId(url, data) {
return $http.patch(url, data, {
transformRequest: transformUpdateData
})
.then(handleUpdateSuccess)
.catch(handleUpdateErrors);
}
Thing is I've tried this every which way I know how. I don't even know how to start debugging any more. I'm just getting 404 on a resource that does exist. Any suggestions on what might be happening to my request would be great.
Resolution:
For anyone having this issue, if you could post the fix or what's going on here to this point or PM me that would be awesome I'd like to know. I ended up just using PUT to fix this.
Quick Restangular solution:
Build the url template for findByOne like function using Restangular.one(url, _id) where '_id', is the id of the resource you're looking for. .get() goes out and finds that one resource by said id, which you can populate dynamically however you like. Once you have the one resource with GET copy it with Restangular.copy() which is different from angular.copy as it doesn't bind 'this' to the new object. Change what needs to be changed or added in the new object and then perform a .put() on it.
var corporiumRecord = Restangular.one('corporium-mgmnts', $scope.uuid);
corporiumRecord.get().then(function(res) {
var update = Restangular.copy(res);
// update date corporiumId
update.corporiumId = $scope.newBlock;
// submit new doc with altered value
update.put().then(function() {
console.log('updated')
});
console.log(update)
}, function(err) {
console.log('Restangular failed: ', err)
});
Also because mongo uses _id and Restangular uses id you have to add this to your module
angular.module('corporium-mgmnts').config(function(RestangularProvider) {
RestangularProvider.setMethodOverriders(['put', 'patch']);
// setRestangularFields is required for mongodb
RestangularProvider.setRestangularFields({
id: "_id"
});
});
Related
In my index.js file I have the following POST...
router.route('/bears')
// create a bear (accessed at POST http://localhost:8080/api/bears)
.post(function(req, res) {
var bear = new Bear(); // create a new instance of the Bear model
bear.name = req.body.name; // set the bears name (comes from the request)
// save the bear and check for errors
bear.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Bear created!' });
});
})
.get(function(req, res) {
Bear.find(function(err, bears) {
if (err)
res.send(err);
res.json(bears);
});
});
I test the url http://localhost:8080/api/bears with a POST request on Postman and it was successful. Now I'd like to test my POST request using angular $resource.
I tried the following which I got from the documentation...
app.factory('Profile', function ($resource) {
var Bear = $resource('http://XXX.XXX.X.XX:3000/api/bears/:bearId', {bearId:'#id'});
var single_bear = Bear.post({bearId:123}, function(){
single_bear.name = "Yogi";
single_bear.$save();
});
});
I'm not sure what I should for bearId, I just put a random number. And I am trying to save the bear's name as Yogi. I'm assuming this POST request will occur when I run the app, but I do so and then check to see if my db was filled and there is no entry.
What am I doing wrong?
EDIT
in case you're wondering what a bear entry looks like...
{
"_id": "57ded2302a5ebc050ce3852d",
"__v": 0,
"name": ""
}
Your resource is configured to look for the id property in the data passed (via '#id') yet your data is passing bearId.
Additionally, the data from your server seems to have an _id property, not id nor bearId.
Also, the resource method you're looking for is save(), not post().
I'd go with this type of resource definition...
$resource('http://XXX.XXX.X.XX:3000/api/bears/:id', {id:'#_id'});
Then, you can use it to create a new Bear via
Bear.save({_id: 123, name: 'Yogi'})
hi in my requirement i tried to write post method using ngresource but now i want to change that into get method. can anyone help me to solve this problem. i am new to angularjs thanks in advance
$scope.clickresult = {};
var Call = $resource('../api/Home', {}, { query: { method: 'POST', isArray: true} });
$scope.click = function () {
//alert("hi");
$scope.selected = "";
var x = $('#txtSearch').val();
var _ReqObj = new Object();
_ReqObj.id = x;
_ReqObj.Meth = "CD";
// alert(x);
Call.query({}, _ReqObj,
function (response) {
if (response == '') {
// alert('no data');
window.location.replace("#/");
}
else {
//alert("daata");
$scope.message = response;
}
},
function (error) {
window.location.replace("#/");
}
);
};
Here is some initial help so you can solve your future problems on your own.
1. Use developer tools to see errors, requests and responses: https://developers.google.com/web/tools/chrome-devtools/
Open the tools from the menu or use cmd+alt+I on Mac or ctrl+shift+I on Windows.
In the "Network" tab of the developer tools you can see the communication with your server (E.g. request method = GET, response from the server). In the "Preview" tab you can see the json the server sent you. Tell me if you have problems finding this, because it is very important to find bugs in your code.
2. Use logging!
In angular you can add $log to your code and with $log.log("message", object) you can output debug messages and the current state of objects from your code. You can see the logging messages in the developer tools in the "Console" tab.
3. Read the documentation
Angular provides documentation and examples for their functions. Read this about the $resource service https://docs.angularjs.org/api/ngResource/service/$resource
Read about the difference between GET and POST method.
4. Try a simple example from a tutorial and try to adapt it to your needs
Copy a simple resource example from the internet and make it work. If that works change it step by step until it is what you need.
5. For your example:
How does your server side script work? In your question I can only see the angular code. If you want to use the GET method the server has to provide a function that reacts to GET.
The $resource service already provides a query method:
{ 'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'} };
Normally you don't need to add "{ query: { method: 'POST', isArray: true}" to your code. The query function is already there!
To send a GET request with the query function you just need:
var Call = $resource('../api/Home', {});
Now open your developer tools, go to the Network tab and then execute the function $scope.click in your website. What do you see in the Network tab? The request should be fired with "request method: GET". What is the answer from the server? The problem is maybe not in your angular code but in your server code.
Try these things and tell me if you need more help.
a really simple example. I have a RESTful api and I setup my resource the following way.
app.factory('apiFactory' , ['$resource', 'GLOBALS',
function($resource, GLOBALS){
return {
Discounts: $resource(GLOBALS.apiPath + 'discounts/:id', {id:'#id'}, {update:{method: 'PUT'}})
}
}
])
And then I call it in a Controller like so
var discountResponse = apiFactory.Discounts.save($scope.discount);
Everything works fine until I add '/:id' to my URL. I do this so that my delete method passes the id along. Like so 'discounts/6'.
The issue that I have is that as soon as I add the placeholder my save() method sends off a GET instead of a POST.
Request URL:http://local:8089/api/discounts
Request Method:GET
Status Code:200 OK
If I remove the placeholder I get
Request URL:http://local:8089/api/discounts
Request Method:POST
Status Code:200 OK
And everything works great, accept for the delete request, which now does not map the placeholder, as it no longer exists.
I have absolutely no idea why. I'm pretty new to $resource, so I am very sure I am not understanding something.
The answer was provided on a differently formulated question and I thought I'd share it.
return {
Discounts: $resource(GLOBALS.apiPath + 'discounts/:id', {id:'#id'} ,{
save: {
method: 'POST', url: GLOBALS.apiPath + "discounts"
},
update: {
method: 'PUT', url: GLOBALS.apiPath + "discounts/:id"
}
})
}
It would seem that for the save() to POST properly I had to define a path in the customConfig object. I'm not sure why this didn't work for me out of the box.
The answer was provided here. Many Thanks!
ngResource save() strange behaviour
I basically call get requests like so:
var resource = $resource('/api/v1/categories/:id')
resource.get({id: 1}).$promise.then(function(data){
console.log(data)
})
This works fine.. but how do I get the response headers?
You could use the transformResponse action defined here this would allow you add the headers
$resource('/', {}, {
get: {
method: 'GET',
transformResponse: function(data, headers){
response = {}
response.data = data;
response.headers = headers();
return response;
}
}
See a working example here JSFiddle
#Martin's answer works for same domain requests. So I would like to add to his answer that if you are using cross domain requests, you will have to add another header with Access-Control-Expose-Headers: X-Blah, X-Bla along with the Access-Control-Allow-Origin:* header.
where X-Blah and X-Bla are custom headers.
Also you do not need to use transform request to get the headers. You may use this code:
var resource = $resource('/api/v1/categories/:id')
resource.get({id: 1}, function(data, headersFun){
console.log(data, headersFun());
})
See this fiddle.
Hope this helps !!!
Old question, but i think it's worth mentioning for the future reference.
There is 'official' solution for this in angular documentation:
It's worth noting that the success callback for get, query and other
methods gets passed in the response that came from the server as well
as $http header getter function, so one could rewrite the above
example and get access to http headers as:
var User = $resource('/user/:userId', {userId:'#id'});
var users = User.query({}, function(users, responseHeaders){
// ...
console.log(responseHeaders('x-app-pagination-current-page'));
});
(code from docs slightly updated for clarity)
For CORS requests, exposing headers as mentioned in other answers is required.
im having trouble using the angular js jsonp function, i cant make this plunk to work:
http://plunker.co/edit/xQVBchTYOro1CB979021
can anyone help me?
With the JSONP "hack" you must make sure that the server's response contains callback's invocation. To make your example work you should change the prov.json file so it looks like follows:
angular.callbacks._0({
"id": "40796308305",
"about": "The Coca-Cola Facebook Page is a collection of your stories showing how people from around the world have helped make Coke into what it is today.",
...
})
There are many sources on JSONP, ex.: What is JSONP all about?
using a get instead of jsonp, you get the details of cokacola...
async: function(page) {
var url = 'prov.json';
var promise = $http.get(url).error(function (response, status) {
alert("fai");
}).success(function (response, status) {
alert(response.about);
}).then(function (response, status) {
return response.data;
});
return promise;
}};