0

I'm using AngularJS and I need to have a global several global objects that can be accessed by any controller in the app.

For example one object that i need is a user object that has the users id and other properties. This user object comes from the database via ajax. So I need a way to set that user object, then initialize the controllers used on the page. Basically giving the app a page load for the fist load of the program.

Then if that object isn't set, I need to redirect.

Does anyone have an idea of how to do this cleanly? I've been trying to use broadcast but its truing into spaghetti code.

Currently I use ui-router, and have a hidden view with a controller GlobalsCtrl. GlobalsCtrl uses a service to get the objects and then $broadcasts them so controllers can initialize. But.... This broadcast only works on the initial site load. When changing $location.paths that event is not broadcast because the GlobalsCtrl variables are already set.

I could add some if statements but that seems messy to me.

Please help. Thanks!


Plunker - http://plnkr.co/edit/TIzdXOXPDV3d7pt5ah8i

var app = angular.module('editor.services', []);
app.factory('AnalysisDataService', ['$http', function($http) {
    var self = this;

    self.activeAnalysis = {};

    self.openAnalysis = function(analysisId) {
        return $http.get('api/v1/assignments/analysis/' + analysisId)
            .success(function(data, status, headers, config) {
                self.activeAnalysis = data;
                return self.activeAnalysis;
            }).error(function(data, status, headers, config) {
                console.log("Error could not load analysis article.");
            }).then(function(result) {
                return self.activeAnalysis;
            });
    };

    self.getAnalysis = function() {
        return self.activeAnalysis;
    };

    self.navigateToStep = function(step) {
        $location.path('/analysis/summary');
    };        

    return {
        open: self.openAnalysis,
        get: self.getAnalysis,
        navigate: self.navigateToStep,
    }
}]);

The problem is I need the self.activeAnalysis variable to be set before a few other controllers load. Each page loads a different data-set based on the analysisId.

RachelD
  • 4,072
  • 9
  • 40
  • 68
  • 3
    Show some code of what you currently have. Sounds like you just want a shared service you can inject across the board. – tymeJV Nov 14 '14 at 16:01
  • 2
    [angular service](https://docs.angularjs.org/guide/services) is the right concept to pickup for shared objects for all controller/directives. angular services are singltons. for example, you can use `$http` service to handle all AJAX requests, use `$cookies` service to read/write browser cookies. You can create a `user` service to read visitor information for all controllers. – shawnzhu Nov 14 '14 at 16:15
  • Hi I added a Plunker with my files: http://plnkr.co/edit/TIzdXOXPDV3d7pt5ah8i – RachelD Nov 14 '14 at 16:16
  • But what do I do when controllers need the variable to be loaded in order to make ajax calls themselves? That's a lot of watch statements. – RachelD Nov 14 '14 at 16:17
  • Promise chaining can take care of that. In `ngRoute`, it is also possible to delay route resolution until some promise resolves, so then your controller won't be initialized until you have the data. Sorry for the brief answer -- I don't have time for more. HTH. – Thomas Nov 14 '14 at 16:21
  • @RachelD: The point shawnzhu is making is that you abstract out your Ajax calls into an service module that you can inject into the controllers that need it. The controllers call the methods of the service to get the data they need for the view. – Brett Nov 14 '14 at 16:24
  • [This question](http://stackoverflow.com/questions/12505760/processing-http-response-in-service) may help. Basic intro to using promises in a service. In my code, I've also used [`$q`](https://docs.angularjs.org/api/ng/service/$q) to wrap validation around the `$http` promise and return a new promise. – Blazemonger Nov 14 '14 at 16:27

2 Answers2

1

ui-router has a resolve method that you can use in your routes.
The resolve will tell the routing to wait and resolve something before it moves to the new route.

Here are some examples(Your problem is similar to authentication):

Community
  • 1
  • 1
Amir Popovich
  • 29,350
  • 9
  • 53
  • 99
1

One thing you can do is to use a resolve on the route with ui.router, ensuring that any promises are resolved before transitioning to the new state. Something like this:

.state('app.mymodule', {url: '/my-route/',
    views:{
      'someView': {
        templateUrl: '/views/someView.html',
        controller: 'someController'
      }
    },
    resolve: { 
      someResolve: function (someService) {
        return someService.getUserInfo();
      }
    }
  })

Here, the $http call done in someService.getUserInfo() will be resolved before transitioning to that state. Inside that method, just set the data from the response in the service, and it will be available in the controller.

reptilicus
  • 10,290
  • 6
  • 55
  • 79