$http.get call error function from success - javascript

I do not have the ability to change an endpoint, and it will return a 200 OK response with different data if it fails. How can I make it run the error function (The 2nd function in a then from a promise)?
MyService service:
self.getData = function() {
return $http.get('/api/controller/action').then(function(x) {
//This will be run even on failure. How can I call....
return x.data;
}, function(x) {
//......here, from the front-end, so that, the 2nd function in
//inside the 'then' in the controller is run.
//This code will currently never run as it never fails server side.
return x;
});
};
controller:
MyService.getData().then(function(x) {
//Success
}, function(x) {
//Failure
});

Use $q.reject, eg
return $http.get('/api/controller/action').then(function(x) {
if (x.data === 'some error condition') {
return $q.reject(x);
}

you can also check status of response you are getting after hitting the API ,
like, means there is some problem in API
if(status!=200){
// do something
}

Related

How to test done part of ajax in jasmine

I really like this resource for AJAX in general and it works in terms of testing a success or error function that's within the AJAX parameters.
However, when I instead choose to not have a $.ajax({ ... success: ... }) and choose to have a .done() outside, I'm not sure how to test. Please help amend my simple spec, thanks!
Code
function itWorked() {}
function sendRequest(callbacks, configuration) {
$.ajax({}).done(function(response) {
itWorked()
});
}
Spec
fdescribe("Ajax Tests", function() {
beforeEach(function() {
spyOn(window, "itWorked")
deferred = $.Deferred().done(function() { })
spyOn($, "ajax").and.callFake(deferred)
sendRequest()
})
it("should work", function() {
expect($.ajax).toHaveBeenCalled() // pass
expect(window.itWorked).toHaveBeenCalled(); // fail
});
});
Well, probably the example in the question is not the same you are running local, but it should fail in the line spyOn($, "ajax").and.callFake(deferred) because callFake expect a function and deferred is not. Instead, deferred should be a resolved Promise and use .and.returnValue instead of .and.callFake.
Here is a working example:
function itWorked() {
console.log("It worked!!");
}
function sendRequest(callbacks, configuration) {
$.ajax({}).done(function(response) {
itWorked();
});
}
describe("Ajax Tests", () => {
beforeEach(function() {
spyOn(window, "itWorked").and.callThrough();
deferred = $.Deferred().resolve(); // Call resolve
spyOn($, "ajax").and.returnValue(deferred); // Use return value
sendRequest();
});
it("should work", function() {
expect($.ajax).toHaveBeenCalled(); // pass
expect(window.itWorked).toHaveBeenCalled(); // pass
});
});
Note that I've added console.log("It worked!!"); and use .and.callThrough(); just to double check in the console that "It worked!!" was logged.
When calling $.Deferred().resolve() you can pass a mocked response to deal with in your .done or .then callback. Something like .resolve({ success: true }). Check an example here
Hope it helps

Recall $resource factory within interception

I have the following factory:
.factory('Request', ['$resource', 'general',
function ($resource) {
return $resource(baseURL + ':resourceName/', {}, {
get : {
method : 'GET',
isArray : true,
transformResponse : function (data, headers) {
return JSON.parse(data).data;
},
interceptor: {
responseError : function (data) {
gnrl.logIn({},false,function(){console.log("test");});
// ???? How to recall this request?
}
}
}
});
}
]);
What I'm trying to do is, if the user has some trouble in this request, the user should login again and the request should be executed again.
The request factory is called as follows:
Request.get(params, headers, function (res) {
//does some operation with results
});
I have seen some related questions but none of them could fit my situation completely.
It is solved using the answers referred in the question. As said, the main idea was using $promise instead of interceptor.
I have solved the problem as follows:
The following is a function in my service
self.doRequest = function(nOfRetries, params, successFunction) {
function fai(a) {
nOfRetries--;
self.logIn(function(){self.doRequest(nOfRetries);});
}
if (nOfRetries >= 0) {
Request.get(params).then(successFunction).catch(fai);
}
}
Login is just another function in the same service and as a callback function i send a request to this function.
doRequest is called as follows:
general.doRequest(3, params/*parameters used in request*/, function (res) {
/***cb function for your initially request*/
});
As last, you see the Request factory:
.factory('Request', ['$resource',
function ($resource) {
var res = $resource(baseURL + ':resourceName/', {}, {
get : {
method : 'GET'
}
});
return {
get : function (arguments) {
return res.get(arguments).$promise;
}
};
}
])
Note that any error (server-side or not) occurred in doRequest's success callback function will also lead to executing failure callback function.

how to remove 404 error in angular js?

.factory('ChartService', ['$http','$q',
function ChartService($http,$q) {
// interface
// implementation
var canceler = $q.defer();
function getTableData() {
return $http.post('http://202.429.115.52:9906/oo/api.php?request=getSubfunctionWiseHCAndSW').success(function (data) {
if (data.mm == "No Data Available"){
localData();
}
return data;
}).error(function(error){
alert("error")
canceler.resolve();
localData()
// console.log(error)
});
}
function localData(){
alert("loaddata")
return $http.get('vro/hcswc.json').success(function(response){
console.log(response+"==");
return response;
}).error(function(error){
console.log(error);
});
}
return {
getTableData:getTableData
}
}
]);
Error
XMLHttpRequest cannot load http://192.127.215.52:9906/api.php?request=getSubfunctionrection. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access. The response had HTTP status code 404.
App.js // resolve Code
.state('app.vro', {
url: "/vro/:isfirstActiveState",
views: {
'menuContent': {
controller: "vrobCtrl",
templateUrl: 'vrob/vrob.html'
}
} ,
resolve: {
tableData:function(ChartService){
return ChartService.getTableData();
}
}
})
Hello
I am trying to get data form service .I have one condition while calling webservice .the condition is if I will get error then I get request from local in other words if I get any error from server than I need to read json file from local . I need to use resolve and call my service and use that data on controller .my localData is not returning data to resolve .what is the problem in my code ..
here is one example
http://plnkr.co/edit/0y9V0m2hmsUBRXoeyjig?p=preview
I am getting error correct but it should load data from local json .why it is not loading data from local json
It is an anti-pattern to use $q to manage $http requests but in this situation I don't know another way:
function getTableData() {
var deferred = $q.defer();
$http.post('http://202.129.215.52:9906/mondelez/api.php?request=getSubfunctionWiseHCAndSW')
.then(
// resolve callback
function(data) {
deferred.resolve(data.data)
return data.data;
},
// reject callback make different request
function(err) {
$http.get('data.json').success(function(response) {
deferred.resolve(response);
}).error(function(error) {
deferred.reject()
});
})
return deferred.promise;
}
DEMO

Check network and handle empty error object

I am using Parse.com as a backend for an Ionic Framework App which means I have to monitor the network activity. I can handle online / offline by using this guide. However, I need a more 'app wide' solution checks on each call. I'm currently getting errors when there is no network as the response from the server is null causing the following error:
Error: null is not an object (evaluating 'response.error')
My question is two fold:
Is it possible to create a network factory / service that I can inject into my ParseFactory to check and notify the user that their network is insufficient.
Handle a null response object in this code:
ParseFactory.provider('Programme/').get($stateParams.loadProgramme).success (function(data){
// do something with success...
}).error(function(response){
$rootScope.$emit('errorEvent',
{"message" : "Unable to load Programme. Please check your connection", "errorObject": response.error}
);
});
My Factory for Parse calls is below:
.factory('ParseFactory',['$http','PARSE_CREDENTIALS',function($http,PARSE_CREDENTIALS){
var baseUrl = 'https://api.parse.com/1/classes/';
return {
provider:function(type, queryParam, queryValue) {
console.log(queryValue);
whereQuery = {}
whereQuery[queryParam] = queryValue;
var masterQuery = {'userId': masterKey};
return {
getAll:function(){
return $http.get(getUrl(type),getParams(whereQuery));
},
getMasters:function(){
return $http.get(getUrl(type),getParams(masterQuery));
},
get:function(id){
return $http.get(getUrl(type)+id,getParams());
},
create:function(data){
return $http.post(getUrl(type),data,getParams());
},
edit:function(id,data){
return $http.put(getUrl(type)+id,data,getParams());
},
delete:function(id){
return $http.delete(getUrl(type)+id,getParams());
}
}
function getUrl(type) {
return baseUrl+type;
}
function getParams(user) {
return {
timeout : 5000,
headers:{
'X-Parse-Application-Id': PARSE_CREDENTIALS.APP_ID,
'X-Parse-REST-API-Key':PARSE_CREDENTIALS.REST_API_KEY,
'X-Parse-Session-Token': Parse.User.current()._sessionToken,
'Content-Type':'application/json'
},
params: {
where: user,
// limit: 2,
// count: 1
// include: "something"
}
}
}
}
}
}])
Use a $http interceptor. All requests using $http are passed through interceptors, so by using interceptors you can apply global handling for successful or unsuccessful requests and responses.
For example, this interceptor cancels a request if the network connection is not available and emits an event when an empty response is received:
app.factory('networkActivityInterceptor', function($rootScope, $q, networkMonitorService) {
return {
'request': function(config) {
var canceller = $q.defer();
config.timeout = canceller.promise;
if (!networkMonitorService.hasNetworkConnection()) {
// cancels the request if there is no network connection
canceller.resolve();
}
// otherwise, let the request go through as normal
return config;
},
'response': function(response) {
// handle a null/empty response
if (!response.data) {
$rootScope.$emit('errorEvent', {
message: 'Unable to load...',
errorObject: response.error
});
}
return response;
},
'responseError': function(response) {
// the response handling above could also be done in the responseError
// handler which is hit when an error HTTP code is returned. (example: 404, 500)
// this depends on what your server is configured to return.
// note that in a responseError handler you must return a rejected promise
// (i.e. return $q.reject(response);)
}
};
});
Substitute networkMonitorService.hasNetworkConnection() for your app's network activity logic.

ExpressJS why is my GET method called after my DELETE method?

In my express app, when the DELETE method below is called, the GET method is immediately called after and it's giving me an error in my angular code that says it is expected an object but got an array.
Why is my GET method being called when i'm explicitly doing res.send(204); in my DELETE method and how can I fix this?
Server console:
DELETE /notes/5357ff1d91340db03d000001 204 4ms
GET /notes 200 2ms - 2b
Express Note route
exports.get = function (db) {
return function (req, res) {
var collection = db.get('notes');
collection.find({}, {}, function (e, docs) {
res.send(docs);
});
};
};
exports.delete = function(db) {
return function(req, res) {
var note_id = req.params.id;
var collection = db.get('notes');
collection.remove(
{ _id: note_id },
function(err, doc) {
// If it failed, return error
if (err) {
res.send("There was a problem deleting that note from the database.");
} else {
console.log('were in delete success');
res.send(204);
}
}
);
}
}
app.js
var note = require('./routes/note.js');
app.get('/notes', note.get(db));
app.post('/notes', note.create(db));
app.put('/notes/:id', note.update(db));
app.delete('/notes/:id', note.delete(db));
angularjs controller
$scope.delete = function(note_id) {
var note = noteService.get();
note.$delete({id: note_id});
}
angularjs noteService
angular.module('express_example').factory('noteService',function($resource, SETTINGS) {
return $resource(SETTINGS.base + '/notes/:id', { id: '#id' },
{
//query: { method: 'GET', isArray: true },
//create: { method: 'POST', isArray: true },
update: { method: 'PUT' }
//delete: { method: 'DELETE', isArray: true }
});
});
** UPDATE **
To help paint the picture, here's the angular error i'm getting:
Error: [$resource:badcfg] Error in resource configuration. Expected response to contain an object but got an array http://errors.angularjs.org/1.2.16/$resource/badcfg?p0=object&p1=array
I'm assuming that i'm getting this error because my delete method is calling my get method (somehow) and the get method returns the entire collection.
Server side
You're removing an element from a collection in your delete function. This is done asynchronously and calling your callback when it's finished.
During this time, other requests are executed, this is why your GET request is executed before your DELETE request is finished.
The same happens in your get function, you're trying to find an element from a collection and this function is too asynchronous.
But this is server side only and it is fine, it should work this way, your problem is located client side.
Client side
If you want to delete your note after you got it, you will have to use a callback function in your angular controller which will be called only when you got your note (if you need help on that, show us your noteService angular code).
This is some basic javascript understanding problem, actions are often made asynchronously and you need callbacks to have an execution chain.
Maybe try doing something like this:
$scope.delete = function(note_id) {
var note = noteService.get({ id: note_id }, function()
{
note.$delete();
});
}
Your code doesn't make sense though, why is there a get in the $scope.delete? Why not do as simply as following:
$scope.delete = function(note_id) {
noteService.delete({ id: note_id });
}
Error
I think you get this error because of what your server sends in your exports.delete function. You're sending a string or no content at all when angular expects an object (a REST API never sends strings). You should send something like that:
res.send({
results: [],
errors: [
"Your error"
]
});

Categories

Resources