1

I'm pretty new with Angular and I'm stuck on this for a few days now :( I have a web app (kind of portal with several web tools available). I want to load some data from DB when the app being initially accessed and use the data in some controller (.i.e. load the data only once).

This is what I have by now:

Main app

 var myApp= angular.module('MyApp',['ngRoute','ngTable','mpcApp','registerApp','forgotPasswordApp','tool1App','loginApp','userManagementApp','init']);

 myApp.config(['$routeProvider','$locationProvider',function($routeProvider) {
  $routeProvider.
    when('/...', {
      templateUrl: 'js/....html',
      controller: 'tool1Ctrl'
    })....

I also have myApp.run - but I will describe it later.

I've created different module for my factory:

    (function (angular) {    

    var initApp = angular.module('init',[]);

    initApp.factory('EndPoints', ['$http', function($http) {
        var EndPointsList="";
        return{
            getList: function(){
                $http.post("/getEndPoints", {
                    transformRequest : angular.identity,
                    headers : {'Content-Type' : undefined}
                }).

                success(function(data, status, headers, config) {               
                EndPointsList = data;
                    console.log(EndPointsList);
                    return EndPointsList;

                }).error(function(data, status, headers, config) {
                    console.log("Failed to load end-points list");                      

                                });
                return EndPointsList;
            }
        };

    }]);
})(angular);

What I did next is injecting this factory into myApp.run:

myApp.run(['$rootScope', '$location', 'SessionIdService','EndPoints', function($rootScope, $location, SessionIdService,EndPoints) {

    $rootScope.EndPoint= EndPoints.getList();
    console.log("Current end-point: " + $rootScope.appEnv);
...

This is just not working! I don't see the print in console at all, and when I try to use the $scope.EndPoint in another controller in another module it appears to be empty.

Controller code:

    var Tool1Controllers= angular.module('tool1App',[]);
    Tool1Controllers.controller('toolCtrl', ['$scope', '$http','$rootScope', function ($scope, $http,$rootScope) {

console.log("Test: Controller end-point: " + $scope.EndPoint);

Please help! :(

4
  • 2
    Maybe you can try to use ui-router and using the resolve feature. github.com/angular-ui/ui-router/wiki Commented Nov 30, 2015 at 14:12
  • 1
    You are returning an empty string in EndPoints since you aren't 1) returning a promise and 2) waiting for the promise to resolve. Commented Nov 30, 2015 at 14:45
  • @Shaohao Lin - thanks, trying to read about it and understand how exactly it works. Commented Nov 30, 2015 at 15:32
  • 1
    @lux - yes, you are correct. Trying to resolve this.. Commented Nov 30, 2015 at 15:32

1 Answer 1

2

The problem seems to be that you are returning a string before $http promise is fulfilled. You need to wait for the http response before returning data, or return the promise and let the consumers implement the outcome handlers.

Try updating your factory as follows:

initApp.factory('EndPoints', ['$http', function($http) {
    return{
        getList: function(){
            return $http.post("/getEndPoints", {
                transformRequest : angular.identity,
                headers : {'Content-Type' : undefined}
            });
        }
    };

}]);

And your run assignment as:

EndPoints.getList()
    .success(function(data, status, headers, config) {               
        $rootScope.EndPoint= data;
    }).error(function(data, status, headers, config) {
        console.log("Failed to load end-points list");                      
    });

UPDATE: An alternative to attaching data to the $rootScope is to have the factory cache the data and offer a method to return the data either from cache or from the remote endpoint if it hasn't already been cached:

initApp.factory('EndPoints', ['$http', '$q', function($http, $q) {
    var endpoints = null;

    return{
        getList: function() {
            return endpoints ?
                // if data is already cached, return it
                $q(function(resolve, reject) { resolve(endpoints); }) :
                // otherwise fetch it from the service, cache it and return it
                $http.post("/getEndPoints", {
                    transformRequest : angular.identity,
                    headers : {'Content-Type' : undefined}
                }).then(function(data) { endpoints = data; return data; });
        }
    };

}]);

And now in your controllers, you can just inject the service and define outcome handlers for the getList promise:

.controller ...

EndPoints.getList()
    .then(function(data) {               
        $scope.someVariable = data;
    }, function(error) {
        console.log("Failed to load end-points list");                      
    });

...

Since factories are singletons, you can inject the Endpoints service into any number of controllers and the same cached data should be returned so that at most 1 call to the remote endpoint is made.

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

6 Comments

thanks for this! Now I actually get a result in .run, but for some reason I can't get the value in the controller. I assumed that if I put the data in $rootScope.EndPoint, I'll be able to access it in ever other modul by using &scope.EndPoint, but it is still undefined. I guess the RUN part happens after the contoller is resolved. Maybe I have to define RESOLVE in $routeProvider? I can't figure out how to do it?..
I would actually recommend not attaching data to the $rootScope unless you really need to. In your case, I would instead just cache the data in the factory and expose a method that either retrieves it from the cache, if available or pulls it from the getEndpoints service. I will update my answer to show this.
The thing is that this controller responsible for a view with a drop down list. I have to have the list of end points ready before the view is up, so that the dropdown list will be filled. Does it make sense? I just tried your suggestion and it doesn't seem to be working :( Sorry, for so many questions and thanks a lot for your help!
I understand. The angular way to solve that issue, as @Shaohao Lin already pointed out is to resolve your data dependencies in your route so that when your controller is instantiated, it is guaranteed to have the data available. I am a ui-router user, so I can show an example of how to do it if you are also using ui-router.
I'm not, but I will be, if this what will make this whole thing work:))) Please show me :)
|

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.