37

I have the following code in the controller.js,

var myApp = angular.module('myApp',[]); myApp.service('dataService', function($http) { delete $http.defaults.headers.common['X-Requested-With']; this.getData = function() { $http({ method: 'GET', url: 'https://www.example.com/api/v1/page', params: 'limit=10, sort_by=created:desc', headers: {'Authorization': 'Token token=xxxxYYYYZzzz'} }).success(function(data){ return data }).error(function(){ alert("error"); }); } }); myApp.controller('AngularJSCtrl', function($scope, dataService) { $scope.data = dataService.getData(); }); 

But, I think I m probably making a mistake with CORS related issue. Can you please point me to the correct way to make this call? Thanks much!

1
  • 1
    This is a super common one to run into :) Commented Dec 21, 2014 at 20:32

7 Answers 7

77

First, your success() handler just returns the data, but that's not returned to the caller of getData() since it's already in a callback. $http is an asynchronous call that returns a $promise, so you have to register a callback for when the data is available.

I'd recommend looking up Promises and the $q library in AngularJS since they're the best way to pass around asynchronous calls between services.

For simplicity, here's your same code re-written with a function callback provided by the calling controller:

var myApp = angular.module('myApp',[]); myApp.service('dataService', function($http) { delete $http.defaults.headers.common['X-Requested-With']; this.getData = function(callbackFunc) { $http({ method: 'GET', url: 'https://www.example.com/api/v1/page', params: 'limit=10, sort_by=created:desc', headers: {'Authorization': 'Token token=xxxxYYYYZzzz'} }).success(function(data){ // With the data succesfully returned, call our callback callbackFunc(data); }).error(function(){ alert("error"); }); } }); myApp.controller('AngularJSCtrl', function($scope, dataService) { $scope.data = null; dataService.getData(function(dataResponse) { $scope.data = dataResponse; }); }); 

Now, $http actually already returns a $promise, so this can be re-written:

var myApp = angular.module('myApp',[]); myApp.service('dataService', function($http) { delete $http.defaults.headers.common['X-Requested-With']; this.getData = function() { // $http() returns a $promise that we can add handlers with .then() return $http({ method: 'GET', url: 'https://www.example.com/api/v1/page', params: 'limit=10, sort_by=created:desc', headers: {'Authorization': 'Token token=xxxxYYYYZzzz'} }); } }); myApp.controller('AngularJSCtrl', function($scope, dataService) { $scope.data = null; dataService.getData().then(function(dataResponse) { $scope.data = dataResponse; }); }); 

Finally, there's better ways to configure the $http service to handle the headers for you using config() to setup the $httpProvider. Checkout the $http documentation for examples.

Sign up to request clarification or add additional context in comments.

2 Comments

@Kevin: I'm newbie ANG, and it's not clear to me, why don't you use .success and .error methods in the service in your re-worked code? do we need to use it in the controller? how ? any sample to show the success/error and the data,config parameters?
I use .then() which is the promise interface which is basically the same as .success() but chain-able. .success/.error are basically deprecated for promises
9

I suggest you use Promise

myApp.service('dataService', function($http,$q) { delete $http.defaults.headers.common['X-Requested-With']; this.getData = function() { deferred = $q.defer(); $http({ method: 'GET', url: 'https://www.example.com/api/v1/page', params: 'limit=10, sort_by=created:desc', headers: {'Authorization': 'Token token=xxxxYYYYZzzz'} }).success(function(data){ // With the data succesfully returned, we can resolve promise and we can access it in controller deferred.resolve(); }).error(function(){ alert("error"); //let the function caller know the error deferred.reject(error); }); return deferred.promise; } }); 

so In your controller you can use the method

myApp.controller('AngularJSCtrl', function($scope, dataService) { $scope.data = null; dataService.getData().then(function(response) { $scope.data = response; }); }); 

promises are powerful feature of angularjs and it is convenient special if you want to avoid nesting callbacks.

3 Comments

$http already returns a promise. Wrapping $http in another promise is redundant.
using .then on the $http promise wont return the data directly like .success does
I followed exactly as above, but ended up with error 'Cannot read property 'then' of undefined' in controller. fix: remove deferred/promise completely and simply return $http(<content goes here>); as mentioned in 1st comment
4

No need to promise with $http, i use it just with two returns :

 myApp.service('dataService', function($http) { this.getData = function() { return $http({ method: 'GET', url: 'https://www.example.com/api/v1/page', params: 'limit=10, sort_by=created:desc', headers: {'Authorization': 'Token token=xxxxYYYYZzzz'} }).success(function(data){ return data; }).error(function(){ alert("error"); return null ; }); } }); 

In controller

 myApp.controller('AngularJSCtrl', function($scope, dataService) { $scope.data = null; dataService.getData().then(function(response) { $scope.data = response; }); }); 

Comments

2

Try this

myApp.config(['$httpProvider', function($httpProvider) { $httpProvider.defaults.useXDomain = true; delete $httpProvider.defaults.headers.common['X-Requested-With']; } ]); 

Just setting useXDomain = true is not enough. AJAX request are also send with the X-Requested-With header, which indicate them as being AJAX. Removing the header is necessary, so the server is not rejecting the incoming request.

Comments

1

So you need to use what we call promise. Read how angular handles it here, https://docs.angularjs.org/api/ng/service/$q. Turns our $http support promises inherently so in your case we'll do something like this,

(function() { "use strict"; var serviceCallJson = function($http) { this.getCustomers = function() { // http method anyways returns promise so you can catch it in calling function return $http({ method : 'get', url : '../viewersData/userPwdPair.json' }); } } var validateIn = function (serviceCallJson, $q) { this.called = function(username, password) { var deferred = $q.defer(); serviceCallJson.getCustomers().then( function( returnedData ) { console.log(returnedData); // you should get output here this is a success handler var i = 0; angular.forEach(returnedData, function(value, key){ while (i < 10) { if(value[i].username == username) { if(value[i].password == password) { alert("Logged In"); } } i = i + 1; } }); }, function() { // this is error handler } ); return deferred.promise; } } angular.module('assignment1App') .service ('serviceCallJson', serviceCallJson) angular.module('assignment1App') .service ('validateIn', ['serviceCallJson', validateIn]) }()) 

Comments

1

Using Google Finance as an example to retrieve the ticker's last close price and the updated date & time. You may visit YouTiming.com for the run-time execution.

The service:

MyApp.service('getData', [ '$http', function($http) { this.getQuote = function(ticker) { var _url = 'https://www.google.com/finance/info?q=' + ticker; return $http.get(_url); //Simply return the promise to the caller }; } ] ); 

The controller:

MyApp.controller('StockREST', [ '$scope', 'getData', //<-- the service above function($scope, getData) { var getQuote = function(symbol) { getData.getQuote(symbol) .success(function(response, status, headers, config) { var _data = response.substring(4, response.length); var _json = JSON.parse(_data); $scope.stockQuoteData = _json[0]; // ticker: $scope.stockQuoteData.t // last price: $scope.stockQuoteData.l // last updated time: $scope.stockQuoteData.ltt, such as "7:59PM EDT" // last updated date & time: $scope.stockQuoteData.lt, such as "Sep 29, 7:59PM EDT" }) .error(function(response, status, headers, config) { console.log('@@@ Error: in retrieving Google Finance stock quote, ticker = ' + symbol); }); }; getQuote($scope.ticker.tick.name); //Initialize $scope.getQuote = getQuote; //as defined above } ] ); 

The HTML:

<span>{{stockQuoteData.l}}, {{stockQuoteData.lt}}</span> 

At the top of YouTiming.com home page, I have placed the notes for how to disable the CORS policy on Chrome and Safari.

Comments

0

When calling a promise defined in a service or in a factory make sure to use service as I could not get response from a promise defined in a factory. This is how I call a promise defined in a service.

myApp.service('serverOperations', function($http) { this.get_data = function(user) { return $http.post('http://localhost/serverOperations.php?action=get_data', user); }; }) myApp.controller('loginCtrl', function($http, $q, serverOperations, user) { serverOperations.get_data(user) .then( function(response) { console.log(response.data); } ); }) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.