3

I have a factory called "Server" which contains my methods for interaction with the server (get/put/post/delete..). I managed to login and get all data successfully when I had all my code in my controller. Now that I want to separate this code and restructure it a little bit I ran into problems. I can still login and I also get data - but data is just printed; I'm not sure how to access the data in controller? I saw some ".then" instead of ".success" used here and there across the web, but I don't know how exactly.

This is my factory: (included in services.js)

app.factory('Server', ['$http', function($http) {
    return {
        // this works as it should, login works correctly
       login: function(email,pass) {
            return $http.get('mywebapiurl/server.php?email='+email+'&password='+pass').success(function(data) {
                console.log("\nLOGIN RESPONSE: "+JSON.stringify(data));
                if(data.Status !== "OK")
                   // login fail
                   console.log("Login FAIL...");
                else
                   // success   
                   console.log("Login OK...");
                });
        },

        // intentional blank data parameter below (server configured this way for testing purposes)
        getAllData: function() {
            return $http.get('mywebapiurl/server.php?data=').success(function(data) {
                console.log("\nDATA FROM SERVER: \n"+data); // here correct data in JSON string format are printed
            });
        },
    };

}]);

This is my controller:

app.controller("MainController", ['$scope', 'Server', function($scope, Server){ 

   Server.login();   // this logins correctly   

   $scope.data = Server.getAllData(); // here I want to get data returned by the server, now I get http object with all the methods etc etc.

  …. continues … 

How do I get data that was retrieved with $http within a factory to be accessible in controller? I only have one controller.

Thanks for any help, I'm sure there must be an easy way of doing this. Or am I perhaps taking a wrong way working this out?

EDIT: I also need to be able to call factory functions from views with ng-click for instance. Now I can do this like this:

// this is a method in controller
$scope.updateContacts = function(){
    $http.get('mywebapiURL/server.php?mycontacts=').success(function(data) {
        $scope.contacts = data;
    }); 
};

and make a call in a view with ng-click="updateContacts()". See how $scope.contacts gets new data in the above function. How am I supposed to do this with .then method?(assigning returned data to variable)

My question asked straight-forwardly:

Lets say I need parts of controller code separated from it (so it doesn't get all messy), like some functions that are available throughout all $scope. What is the best way to accomplish this in AngularJS? Maybe it's not services as I thought …

2 Answers 2

3

The trick is to use a promise in your service to proxy the results.

The $http service returns a promise that you can resolve using then with a list or success and error to handle those conditions respectively.

This block of code shows handling the result of the call:

var deferred = $q.defer();
$http.get(productsEndpoint).success(function(result) {
    deferred.resolve(result);
}).error(function(result) { deferred.reject(result); });
return deferred.promise;

The code uses the Angular $q service to create a promise. When the $http call is resolved then the promise is used to return information to your controller. The controller handles it like this:

app.controller("myController", ["$scope", "myService", function($scope, myService) {
    $scope.data = { status: "Not Loaded." };
    myService.getData().then(function(data) { $scope.data = data; });
}]);

(Another function can be passed to then if you want to explicitly handle the rejection).

That closes the loop: a service that uses a promise to return the data, and a controller that calls the service and chains the promise for the result. I have a full fiddle online here: http://jsfiddle.net/HhFwL/

You can change the end point, right now it just points to a generic OData end point to fetch some products data.

More on $http: http://docs.angularjs.org/api/ng.%24http More on $q: http://docs.angularjs.org/api/ng.%24q

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

6 Comments

added update to my question. Otherwise, this way I can obtain the data, yeah!
You just move the service call like this: $scope.fetchData = function() { myService.getData().then(function(data) { $scope.data = data; }); }; ... here is an updated fiddle: jsfiddle.net/jeremylikness/HhFwL/2
What is the point of having a service then? If you need to write and use a function in controller as well. hmm, maybe I should just stay within my controller then?
Main advantage is hiding the details of the end point and implementation. You can also intercept errors that return and process them generically and then reuse the calls across multiple controllers. Another advantage is testing - if you have the service wrap $http you can replace it with a mock and test the service.
I know this is an old question but why do we need to use $q if $http itself returns a promise? I am just trying to wrap my head around angular promises.
|
0

$http.get retuns a HttpPromise Object

 Server.getAllData().then(function(results){

   $scope.data = results;
 })

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.