Service.js
myService.serviceName = function (userId) {
return $http({
method: 'POST',
url: '/someUrl'
}).then(function successCallback(response) {
return response.data;
}, function errorCallback(response) {
console.log('Service errorCallback');
console.log(response);
});
};
Controller.js
myService.ControllerName(data.id)
.then(function successCallback(data) {
//do processing here
}, function errorCallback(response) {
toaster.pop({
type: 'error',
title: 'Display Error Message!'
});
});
In service, we are getting error status code in console viz -1, -2 and based on that code we are displaying custom error message to the user.
How do I pass error (message/code) from service to controller ?
The first thing that comes to my mind is to accept callbacks from the Controller.
myService.serviceName = function (userId) {
return $http({
method: 'POST',
url: '/someUrl'
})
};
And in your Controller:
myService.serviceName(123).then(function(response) {
// Do the processing.
}, function(error) {
// Check the error and change the UI accordingly.
});
If you need to make the processing within the service, you might want to use the $q service. In this case, you would need to inject it into your Service.
myService.serviceName = function (userId) {
var defer = $q.defer();
$http({
method: 'POST',
url: '/someUrl'
}).then(function (response) {
// Do the processing.
defer.resolve(response);
}).catch(function (error) {
defer.reject(error);
});
return defer.promise;
};
In your controller:
myService.serviceName(123).then(function(response) {
// Indicate that everything went OK.
}, function(error) {
// Check the error and change the UI accordingly.
});
You could add functionality to add callbacks to the service.
This way the controller can register its own callback method to the service. Which in its turn will call said callback method when the error occurs. Notifying the controller of the occurred error and desired message.
Related
I am calling a method inside a Service and when the work of service is done it should return to controller with the data,
and continue the work further, but after the service is called and data is generated the method is controller stops and return error in console:
Error:
Error: d is undefined
sendOtp/<#http://xxxxxxx:8087/controller/resources/static/js/controller/mainController.js:71:14
processQueue#https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js:14634:28
scheduleProcessQueue/<#https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js:14650:27
$RootScopeProvider/this.$get</Scope.prototype.$eval#https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js:15916:16
$RootScopeProvider/this.$get</Scope.prototype.$digest#https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js:15727:15
$RootScopeProvider/this.$get</Scope.prototype.$apply#https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js:16024:13
done#https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js:10511:36
completeRequest#https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js:10683:7
requestLoaded#https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js:10624:1
CONTROLLER:
app.controller('signController', ['$scope','signUpService','$location','$rootScope', function($scope, signUpService, $location, $rootScope) {
$scope.OTP='';
function sendOtp(pNumber, countryId){
if(pNumber!==null){
$rootScope.pNumber = pNumber;
signUpService.sendPhoneOtp(pNumber,countryId)
.then(
function(d) {
/*$location.path('/otp', false);*/
$scope.OTP = d.response.result.otp;
console.error('OTP SENT SUCCESSFULLY'+$scope.OTP);
alert($scope.OTP);
},
function(errResponse){
console.error('Error while fetching OPT of NUMBER');
}
);
}else{
alert("Number can not be empty");
}
}
METHOD INSIDE SERVICE:
function sendPhoneOtp(pNumber,countryId){
var deferred = $q.defer();
$http({
method: 'POST',
url: 'https://xxxxx.com/service/verify/phone',
data: {
phone: pNumber,
countryId: countryId
}
}).success(function(response){
deferred.resolve(response.data);
}).error(function(errResponse){
console.error('Error while OTP');
deferred.reject(errResponse);
});
return deferred.promise;
}
try to change your sendPhoneOtp function to:
function sendPhoneOtp(pNumber, countryId) {
return $http({
method: 'POST',
url: 'https://xxxxx.com/service/verify/phone',
data: {
phone: pNumber,
countryId: countryId
}
}).then(function(response){
return response.data;
}).catch(function(errResponse) {
console.error('Error while OTP');
});
}
in deprecated success function there is no data property, also you do not need to use $q service, since $http is a promise by itself
I'm new to angular js. Here i have the code: I receive the response data like number. In this code how i assign the response data as $scope.vote_counting. In this code does not return anything.
$scope.votes = function(){
var votes = $http({
method: "post",
url: "/getVotes",
data: { id: $scope.Id}
}).success(function(response){
});
return votes;
}
Please anyone help to this.
Simply call the $http. It does not have to be in a function
$http({
method: "post",
url: "/getVotes",
data: { id: $scope.Id }
}).then(function(response) {
//handle success
$scope.votes_counting = response.data;
}, function(error){
//handle error
});
The sort version is
$http.post("/getVotes", { id: $scope.Id }).then(function(response) {
//handle success
$scope.votes_counting = response.data;
}, function(error) {
//handle error
})
Note : You are using a POST method but a GET method seems more appropriate in your case (getVotes)
I've added a snippet, which shows the basic handling of promises. Here, I've used a service to mock a http call. The response is attached to a scope variable, which is presented in the view.
angular.module('TestApp', [])
.factory('MockHttp', function($q) {
return {
getMockData: function() {
return $q.when(['A', 'B', 'C']);
}
};
})
.controller('TestController', function($scope, MockHttp) {
$scope.res = null;
MockHttp.getMockData()
.then(function(res) {
$scope.res = res;
})
.catch(function(err) {
console.log(err);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="TestApp">
<div ng-controller="TestController">
{{res}}
</div>
</div>
The $http function does not return the response of the server. But as you have already figured out you can use the success function to get the servers response. Simply set $scope.votes value in the success function like this:
$http({
method: "post",
url: "/getVotes",
data: { id: $scope.Id}
}).success(function(response){
$scope.votes = response
});
The easiest is probably using $http.post. Note that success is deprecated in favour of then:
$scope.retrieveVotes = function(){
$http.post('/getVotes', {id : $scope.id}).then(function(response){
$scope.votes = response.data;
});
}
Also note that $http calls are asynchronous so calling retrieveVotes is also asynchronous.
Since I am using ajax request using $http. It takes a long time since my operation on server takes time. I need to show loader while processing request, but the loader does not show. Although my code seems correct. I tried different methods but did not work.
Index.html
<body ng-app="app">
<!-- loader, can be used on multiple pages-->
<div class="loading loader-quart" ng-show="isLoading"></div>
<!-- my logic -->
</body>
addCtrl.js
//method to get all the attributes and send to server using service
$scope.add = function () {
if ($scope.Option == 'newInstance')
$scope.singleObject.FK_Name = 'MetisEmptyTemplate';
$rootScope.isLoading = true;
var featuresList = websiteService.getUpdatedTree($scope.treeDataSource);
var formData = new Website("", $scope.singleObject.Name, $scope.singleObject.DisplayName, $scope.singleObject.Description, $scope.singleObject.State, "", $scope.singleObject.FK_Name, $scope.singleObject.Email, featuresList);
websiteService.addwebsite(formData);
$rootScope.isLoading = false;
}
websiteService.js
//service to add website
this.addwebsite = function (website) {
$http({
method: 'POST',
url: $rootScope.url + 'Add',
data: JSON.stringify(website),
contentType: 'application/json'
}).success(function (data) {
alert(data);
}).error(function (data, status, headers, config) {
//alert(data);
});
}
Since I am going to turn isLoading as "true" in start and then after request completes I turn isLoading "false". Where is the problem in code?
Your websiteServices code gets executed asynchronously. Which means that the above code would display the loader and then pretty much hide it again instantly.
To handle async code in the controller you must return a promise from the service and put the hiding of the spinner in a callback function using .then().
service:
this.addwebsite = function (website) {
var deferred = $q.defer();
$http({
method: 'POST',
url: $rootScope.url + 'Add',
data: JSON.stringify(website),
contentType: 'application/json'
}).success(function (data) {
alert(data);
deferred.resolve(data);
}).error(function (data, status, headers, config) {
//alert(data);
deferred.reject(data);
});
return deferred.promise
}
controller:
websiteService.addwebsite(formData).then(function(){
$rootScope.isLoading = false
});
this.insertMliveResponse = function(data){
var defer=$q.defer();
var requestURL='/mlive-portlet/rest/mliveResponseService/insertmLiveResponse';
httpRequest(requestURL,data).then(function(data){
defer.resolve(data.data);
},function(data){
defer.reject(data.data);
})
return defer.promise;
}
If you are making request then,
I think the best way to show hide loader is interceptor
In my snippet, I am using loader service to activate/deactivate loader
For Eg:
// http.config.js file
export function httpConfig($httpProvider, AuthInterceptProvider) {
'ngInject';
AuthInterceptProvider.interceptAuth(true);
// added for show loader
$httpProvider.interceptors.push(function (loaderService, $q) {
'ngInject';
return {
'request': function (config) {
loaderService.switchLoaderModeOn();
return config;
},
'requestError': function (rejection) {
loaderService.switchLoaderModeOff();
return $q.reject(rejection);
},
'response': function (response) {
loaderService.switchLoaderModeOff();
return response;
},
'responseError': function (rejection) {
loaderService.switchLoaderModeOff();
return $q.reject(rejection);
}
};
});
}
// and in your module.js file
import {httpConfig} from './config/http.config';
.config(httpConfig)
I use the RIOT GAMES API. And I use factories for my API calls. First of all I request the summonerName and then I use this name to get the id of this summonerName.
I tried with:
$scope.summonerId = $scope.summoner.id;
And then access to this $scope but it doesn't work:
I recived this error with and undefined where I should recive the summonerId. (21694436) this is my summonerID :
https://euw.api.pvp.net/api/lol/euw/v1.3/stats/by-summoner/undefined/summary?season=SEASON2016&api_key=foo-bar-foo-bar-foo-bar
I have got the following javascript code:
'use strict';
angular.module('mean.system').controller('SummonerController', ['$scope', '$http','APIAcces', '$stateParams',
function($scope, $http, APIAcces, $stateParams) {
$scope.summonerName = $stateParams.summonerName;
APIAcces.getSummonerByName($scope.summonerName).then(
function successCallback(response) {
$scope.summoner = response.data[$scope.summonerName.toLowerCase()];
$scope.summonerId = $scope.summoner.id;
console.log($scope.summonerId); //returns id successfuly
console.log(response);
}, function errorCallback(error) {
console.log(error);
console.log(response);
},
//if I do.. APIAcces.getSummonerSummary('21694436').then( // it works!
APIAcces.getSummonerSummary($scope.summonerId).then(
function successCallback(response) {
$scope.summoner2 = response.data[$scope.summonerId];
console.log(response);
},function errorCallback(error) {
console.log(error);
console.log(response);
}
) //End APIAcces.getSummonerSummary
); //End APIAcces.getSummonerByName
}
]);
I pass the argument summonerId and this factory it doesn't recognize it.
I use this method:
angular.module('mean.system').factory('APIAcces',['$http','API_KEY',
function($http,API_KEY){
return {
getSummonerByName:function(summonerName){
return $http.get('https://euw.api.pvp.net/api/lol/euw/v1.4/summoner/by-name/'+summonerName+'?api_key='+API_KEY.KEY);
},
getSummonerSummary:function(summonerId){
return $http.get('https://euw.api.pvp.net/api/lol/euw/v1.3/stats/by-summoner/'+summonerId+'/summary?season=SEASON2016&api_key='+API_KEY.KEY);
},
}
}]).value('API_KEY',{
KEY: 'foo-bar-foo-bar-foo-bar'
});
I don't know, maybe it is an order of factories or something?
From your code, it's a typical async callback problem. you may have to first understand javascript callback and async architecture by reading somewhere else.
The reason is because
APIAcces.getSummonerSummary()
is being called when
APIAcces.getSummonerByName()
has not finished fetching, so the summonerId is undefined, it's just an async programming's nature.
so to correct this, you have chain the call together like this:
APIAcces.getSummonerByName($scope.summonerName).then(
function(response){
var summonerId; //extract the id from response
APIAcces.getSummonerSummary(summonerId).then(
function(response){
//response should contain the summary
},
function(error){
//error of getting by id
}
);
},function(error){
//error of getting by name
});
There are two problems. Trimming the contents of your functions shows the first problem:
APIAcces.getSummonerByName($scope.summonerName).then(
function successCallback(response) {
// success
},
function errorCallback(error) {
// failure
},
APIAcces.getSummonerSummary($scope.summonerId).then(
function successCallback(response) {
// inner success
},
function errorCallback(error) {
// outer success
}
)
);
The third parameter is the finally parameter but you are not passing in a function. You should do this:
APIAcces.getSummonerByName($scope.summonerName).then(
function successCallback(response) {
// success
},
function errorCallback(error) {
// failure
},
function finallyCallback() {
APIAcces.getSummonerSummary($scope.summonerId).then(
function successCallback(response) {
// inner success
},
function errorCallback(error) {
// inner failure
}
)
}
);
The second problem is that you probably don't want this in the finally block anyway. If your request fails, you will not have an appropriate summoner id to work with. It should be moved to the success block:
APIAcces.getSummonerByName($scope.summonerName).then(
function successCallback(response) {
// success
APIAcces.getSummonerSummary($scope.summonerId).then(
function successCallback(response) {
// inner success
},
function errorCallback(error) {
// inner failure
}
)
},
function errorCallback(error) {
// failure
}
);
I am doing some http calls in Angular and trying to call a different service function if an error occurs. However, regardless of my original service call function return, the promise it returns is always "undefined". Here is some code to give context:
srvc.sendApplicantsToSR = function (applicant) {
var applicantURL = {snip};
var promise = $http({
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
method: 'POST',
url: applicantURL,
data: applicant
})
.success(function (data) {
return data;
})
.error(function (error) {
return [];
});
return promise;
};
Then, in the controller:
for (var applicant in $scope.applicants) {
$scope.sendATSError($scope.sendApplicantsToSR($scope.applicants[applicant]), applicant);
}
$scope.sendATSError = function (errorCheck, applicantNumber) {
if (angular.isUndefined(errorCheck)) {
console.log(errorCheck);
AtsintegrationsService.applicantErrorHandling($scope.applicants[applicantNumber].dataset.atsApplicantID);
}
};
However, it is always sending errors because every response is undefined. How can I differentiate between the two returns properly? Thank you!
Looking at angular documentation, the sample code is
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
based on that - your first code snippet should be
srvc.sendApplicantsToSR = function(applicant) {
var applicantURL = {
snip
};
return $http({
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
method: 'POST',
url: applicantURL,
data: applicant
});
};
As others have said, $http's .success() and .error() are deprecated in favour of .then().
But you don't actually need to chain .then() in .sendApplicantsToSR() as you don't need (ever) to process the successfully delivered data or to handle (at that point) the unsuccessful error.
$scope.sendApplicantsToSR = function (applicant) {
var applicantURL = {snip};
return $http({
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
method: 'POST',
url: applicantURL,
data: applicant
});
};
Now, in the caller (your line of code in the for loop), a promise is returned (not data) and that promise will, on settling, go down its success path or its error path. Exactly what happens on these paths is determined entirely by the callback functions you write in one or more chained .thens .
So what you need to write is a kind of inside-out version of what's in the question - with $scope.sendApplicantsToSR() on the outside and $scope.sendATSError() on the inside - and linked together with a .then().
for (var prop in $scope.applicants) {
var applicant = $scope.applicants[prop];
$scope.sendApplicantsToSR(applicant).then(null, $scope.sendATSError.bind(null, applicant));
}
// Above, `null` means do nothing on success, and
// `function(e) {...}` causes the error to be handled appropriately.
// This is the branching you seek!!
And by passing applicant, the error handler, $scope.sendATSError() will simplify to :
$scope.sendATSError = function (applicant) {
return AtsintegrationsService.applicantErrorHandling(applicant.dataset.atsApplicantID); // `return` is potentially important.
};
The only other thing you might want to know is when all the promises have settled but that's best addressed in another question.
You should return your promisse to be handled by the controller itself.
Simplifying:
.factory('myFactory', function() {
return $http.post(...);
})
.controller('ctrl', function(){
myFactory()
.success(function(data){
// this is your data
})
})
Working example:
angular.module('myApp',[])
.factory('myName', function($q, $timeout) {
return function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve('Foo');
}, 2000);
return deferred.promise;
}
})
.controller('ctrl', function($scope, myName) {
$scope.greeting = 'Waiting info.';
myName().then(function(data) {
$scope.greeting = 'Hello '+data+'!';
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="ctrl">
{{greeting}}!
</div>