I have an AngularJS app. In this app, I'm trying to ping a REST API. This API returns a list of orders.
I need to be able to handle the scenario where I successfully GET the orders. I also need to handle the
scenario where the request to GET the orders fails. In an attempt to do this, I'm using the ngResource
module. My controller looks like the following:
myController.js
myApp.controller('myController',
function myController($scope, myService) {
myService.getOrders(function(data) {
$scope.orders = data;
});
}
);
The definition of myService is stored in myService.js. That file looks like this:
app.factory("myyService", function($resource, $log) {
return {
getOrders: function(onSuccess) {
var orders = $resource("http://localhost:1000/orders", { fetch:{method:'JSON'} });
orders.fetch(function (response) {
console.log(response);
onSuccess(response.data);
});
}
};
});
When I run this code, I get a runtime error. The error says:
TypeError: Object function g(b){z(b||{},this)} has no method 'fetch'
Maybe there has to be something I don't understand. In my mind, I see fetch defined.
The other question I have is how do I set this up to handle failed requests? Like a 404 or 502?
You forgot the curly braces after the URL parameter...
Change: http://localhost:1000/orders", { fetch :
To: http://localhost:1000/orders", {}, { fetch :
app.factory("myyService", function($resource, $log) {
return {
getOrders: function(onSuccess) {
var orders = $resource("http://localhost:1000/orders", {}, { fetch : {method:'JSON'} });
orders.fetch(function (response) {
console.log(response);
onSuccess(response.data);
});
}
};
});
[EDIT]
To handle errors from the server side, you need to set the second function in the resource call.
Example :
orders.fetch(function success() {...},
function error() {... this will execute in a http error, 400 or 500}
);
Related
I'm writing an ionic v1/express/mongo/node app. When checking if the user is authenticated i have the following piece of code:
checkAuthentication: function(token) {
console.log(token);
return $http.get("http://validUrl/test", {
headers: {
'testingAuth': token
}
}).then(function(result) {
return result.data;
});
}
and am calling it like this:
checkAuthentication(token).then(function(response) {
console.log("testing response: " + response);
// if a valid token is already in storage = response contains "Success"(?), just $state.go to main page, else call the login() function
if (response.content === "Success") {
// $state.go main page
} else {
console.log("could not log in");
}
})
The problem is, when I get back code 401 from the server, I somehow skip the then block in the checkAuthentication function. Execution doesn't stop at a breakpoint at "return result.data", or "console.log("could not log").
Am I doing something obviously wrong? Is there something i need to do to force going into that block? Thanks for any advice.
The issue is with your error handling ! I took the liberty to modify your code and the way to do a $http call. Here is the working plunker for the same.
If you observe the $scope.login() function I've injected the service object and invoked the checkAuthentication() function which does the HTTP call.As you are using .then for http calls, angular provides provision to use two functions for success and error callbacks where your HTTP errors go when HTTP calls fail.
Here is the angular doc for the same.
In your example you don't have error callback method hence it doesn't go into your if else conditions.
var app = angular.module("App", []);
app.controller('AppCtrl', ['$rootScope', '$scope', '$http', 'Service', function($rootScope, $scope, $http, Service) {
$scope.login = function(token) {
//call the injected service in the function for HTTP call..
Service.checkAuthentication(token).then(function(response) {
console.log("testing response: " + response);
// if a valid token is already in storage = response contains "Success"(?), just $state.go to main page, else call the login() function
if (response.content === "Success") {
// $state.go main page
}
},function(error){
console.log(error);
console.log("could not log in due to error...");
});
};
}]);
//use angular services to do a http call for better code maintainability...
app.service('Service', ['$http', '$rootScope', function($http, $rootScope) {
return {
checkAuthentication: function(token) {
return $http.get("http://validUrl/test", {
headers: {
'testingAuth': token
}
});
}
};
}]);
I want to send headers each time for CRUD operation from factory side.
Here is my factory
var appangular.module("LifeStyleFactModule",["ngResource"]);
app.constant("RES_URL", "http://localhost:9090/")
app.factory("CategoryFactory",function($resource,RES_URL){
var categoryinfo;
var categoryresource=$resource(RES_URL+"category/:id",{"id":"#id"},{update:{method:"PUT"}});
return{
getcategory:function(){
categoryinfo=categoryresource.query();
return categoryinfo;
},
addcategoryItem:function(categoryItem){
var category = new categoryresource(categoryItem);
category.$save(function(respdata){
categoryinfo.push(respdata);
},function(respdata){
});
},
deletecategoryItem:function(idx,id){
var category=new categoryresource({"id":id});
category.$delete(function(){
categoryinfo.splice(idx,1);
},function(){
})
},
updatecategoryItem:function(categoryItem,idx){
var category=new categoryresource(categoryItem);
category.$update({"id":categoryItem._id},function(data){
categoryinfo[idx]=data;
},function(){
})
}
}
})
the above functionality is working well. Now i want to send the token in the headers. How can i do that.
I have tried to do it by the following way
var categoryresource=$resource(RES_URL+"category/:id",{"id":"#id"},{update:{method:"PUT"},headers:{"token":"#token}});
but not getting how to send the token for CRUD operation.
Is procedure is correct, if so how can i send tokens.
Else let me know the way.
Instead of above method i tried the following way as
$resource(RES_URL+"category",{},{query:{method:"get",isArray:true,headers:{"token":token}}}).query({},function(res){});
this is working but the procedure for the first procedure.
Please after answering mark it as duplicate or down vote
dont say ( / { such things are missing.
The best solution as to me is to use interceptor. Here is a way to send token in headers, I've used in one of my projects.
angular
.module('app.core')
.config(config);
config.$inject = ['$httpProvider'];
function config($httpProvider) {
$httpProvider.interceptors.push(interceptor);
}
interceptor.$inject = ['$q', '$injector', 'AuthModel'];
function interceptor($q, $injector, AuthModel) {
return {
request: function (config) {
config.headers.Authorization = AuthModel.token;
return config;
},
responseError: function (rejection) {
}
};
}
Added a jsfiddle to demonstrate
https://jsfiddle.net/Sergey_Mell/c47js1zc/
Just click the Send button and check the request headers in developer tools
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 am playing around with the MEAN stack. I have created a rest service to delete from mongo db which works fine but When I try to use angular Factory method and call it I get the above error
myApp.factory('methodFactory', ['$http', function ($http) {
return {
//id becomes undefined over here
removeContact:function($http, id){
//TODO add URL
var url = '/contactlist/'+id;
return $http({
method: 'DELETE',
url: url
});
}
};
}]);
myApp.controller('AppControl', ['$scope','$http','methodFactory', function($scope,$http,methodFactory) {
$scope.remove = function(id) {
console.log(id); //able to print correct id
methodFactory.removeContact(id).success(function(response){
console.log("remv"+response);
refresh();
});//tthiss throws the error
//this rest service works properly.
/*$http.delete('/contactlist/'+id).success(function(response){
console.log("remv"+response);
refresh();
});*/
};
};
This what node server looks like
app.delete('/contactlist/:id',function(req,res) {
var id = req.params.id;
console.log(id);
db.contactlist.remove({_id:mongojs.ObjectId(id)},function(err,doc){
res.json(doc);
});
console.log("exiting delete")
});
I am not sure if factory could be one of the way to call a rest service. What could cause the problem ?
Error
TypeError: string is not a function
at Object.removeContact (http://localhost:3000/controllers/controller.js:10:20)
at l.$scope.remove (http://localhost:3000/controllers/controller.js:85:23)
at hb.functionCall (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js:198:426)
at Cc.(anonymous function).compile.d.on.f (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js:215:74)
at l.$get.l.$eval (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js:126:193)
at l.$get.l.$apply (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js:126:419)
at HTMLButtonElement.<anonymous> (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js:215:126)
at HTMLButtonElement.c (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js:32:363)
Your removeContact method needs two parameters:
removeContact:function($http, id) ...
but you call it with only one:
methodFactory.removeContact(id) ...
Id is a string, I suppose, but it it will be assigned to the first parameter of the function $http, what must be executable according the code you provided.
I have implemented resources in my single page angular app which fires to my REST client server. I have made different services for each resource. Now my REST server is sending a value in response header, now I want to know a proper way where I can retrieve that value from headers.
My service code:
app.service('$job', function($resource) {
var job = $resource(service_base_url+'jobs.json/:id');
return job;
});
My controller which is getting headers:
app.controllerProvider.register('JobPostsController',['$scope','$job', function($scope, $job) {
$scope.jobs = {};
$scope.job_titles = {};
$job.query(function(jobs,responseHeaders){
var headers = responseHeaders();
some_function(headers.user);
$scope.jobs = jobs.jobs;
});
}
]);
I am getting headers in my above code, but I don't want to inject it in all controllers. So is there a proper way to do it? Some single config code which will run for all future resources request or some kind of event which can be only triggered when successful resource response with 200 OK
Try interceptor.
I don't know exactly your logic. You could register a global interceptor which intercepts all requests:
angular.module('App', [])
.config(function ($httpProvider){
$httpProvider.interceptors.push(function() {
return {
'response': function(response) {
var headers = response.headers();
some_function(headers.user);
return response;
}
};
});
});
or just register an interceptor which runs only for all requests of this query.
app.service('$job', function($resource) {
var job = $resource(service_base_url+'jobs.json/:id',{}, {
'query': {
method:'GET',
isArray:true,
interceptor: {
'response': function(response) {
var headers = response.headers();
some_function(headers.user);
return response;
}
}
}
});
return job;
});
Side notes:
Should not use $ prefix for your service name as it's reserved for angular, it may conflict with angular future versions.
I guess you need .factory instead of .service
You can set up the service in a run block like:
angular.module('myApp', [])
.run(['$rootScope', '$job',function ($rootScope, $job) {
$rootScope.jobs = {};
$rootScope.job_titles = {};
$job.query(function(jobs,responseHeaders){
var headers = responseHeaders();
some_function(headers.user);
$rootScope.jobs = jobs.jobs;
});
}]);
The only drawback your service is global to the app
I would go with a base service factory. This would allow you to have common service related functionality in one place
app.factory('ServiceBase', function () {
function ServiceBase() {
this.responseHeaders = function responseHeaders(resp){
// todo
};
}
return ServiceBase;
});
app.service('$job', function($resource, ServiceBase) {
var service = function () {
// $job related functions here
};
angular.extend(service, new ServiceBase());
return service;
});
Now anything in the ServiceBase is accessible to the controller and to the service. This allows you to have common functionality, has no new injection dependencies (on the controller), and is easy to extend further.
I think angulrjs response interceptors can help u for this.