16

I'd like to have a "Global function" called the first time I launch my AngularJS application, or every time I refresh the page.

This function will call my server with $http.get() to get global information necessary to use my application. I need to access $rootScope in this function. After that, and only after this request finished, I'm using app.config and $routeProvider.when() to load the good controller.

app.config(['$routeProvider', function($routeProvider) {
    $routeProvider
        .when('/', 
        {
            /**/
        });
}]);

I don't want the application do something before this action is finished. So I guess I have to use a "resolve", but I don't really know how to use it.

Any idea?

Thanks!

Kenneth Lynne
  • 15,461
  • 12
  • 63
  • 79
alexmngn
  • 9,107
  • 19
  • 70
  • 130
  • 4
    You *cannot* run an `$http` request before running your `config` blocks. The `run` blocks will run immediately *after* the `config` blocks, which is the soonest point you can do this. Also, you shouldn't store the data in `$rootScope`, but in a service. Why do you feel you need the info before setting up routing? – Josh David Miller Apr 01 '13 at 23:37
  • I'm trying to create an international website, multi-languages. 1. Get translations from the server (Global function!) and put those data in the rootScope (all translations, to avoid the user to load translations every time he change of page, and to avoid me to list all keyword I need for each page. If you have another idea to get the list of keywords used in a template and then load translation after the template is loaded that may help me) 2. Setting up routing 3. Execute the controller, display. – alexmngn Apr 02 '13 at 01:39
  • 1
    The translations should be in a service for sure. There services out there if you want something out of the box, like [this one](https://github.com/PascalPrecht/ng-translate) - it should provide inspiration if nothing else. But you still didn't answer why you need the translations before setting up the routing. – Josh David Miller Apr 02 '13 at 01:46
  • I want the translation in the template before this show up. So before the promise is resolved. To avoid the user to see translation will appear from nowhere – alexmngn Apr 02 '13 at 03:36
  • 2
    Routes aren't called when the `$routeProvider` runs; they're called a bit later. You should be fine with a `run` block. The `resolve` runs *before* the view is visible: [demo](http://plnkr.co/edit/EwUgYsnEjR48XvJ2MvOO?p=preview). So your translation service can do its magic there, if necessary. But this belongs in a service and *not* on $rootScope - it won't change when it's visible in the view. – Josh David Miller Apr 02 '13 at 04:00

3 Answers3

24

It's not the best way to solve your given problem, but here is a proposed solution for your question.

Anything inside run(...) will be run on initialization.

angular.module('fooApp').run(['$http', '$rootScope' function($http, $rootScope) {
 $http.get(...).success(function(response) {
     $rootScope.somedata = response;
 });

 $rootScope.globalFn = function() {
   alert('This function is available in all scopes, and views');
 }

}]);

Now an alert can be triggered in all your views, using ng-click="globalFn()".

Be aware that directives using a new isolate scope will not have access to this data if not explicitly inherited: $scope.inheritedGlobalFn = $rootScope.globalFn

Kenneth Lynne
  • 15,461
  • 12
  • 63
  • 79
  • 1
    This does not solve the problem. Any view requiring somedata will most likely need that data before the asynchronous call in run is returned, causing errors. The problem lies with the inability to have anything wait on what is happening in run. What is needed is a universal resolve in AngularJS. This does not exist currently, and I haven't found a clean solution to this problem. – Tim Hardy Sep 25 '13 at 18:40
  • Indeed. If all the controllers had a service injected that responded with the promise that was triggered in Run, it would solve the problem. Will take the time to provide a decent example later! – Kenneth Lynne Sep 26 '13 at 07:45
  • There's a missing comma between `'$rootScope'` & `function($http,` ;) Can't edit though because I need more characters (typo edits are apparently not wanted on SO) – z3ntu Feb 04 '17 at 14:56
3

As a first step for your solution, I think that you could monitor the $routeChangeStart event that is triggered before every route change (or page refresh in your case).

var app = angular.module('myApp').run(['$rootScope', function($rootScope) {
    $rootScope.$on("$routeChangeStart", function (event, next, current) {
        if (!$rootScope.myBooleanProperty)) {
            $location.path('/');
        }
        else {
            $location.path('/page');
        }
    });
});

You should have a look at this article about Authentification in a Single Page App. I think you could work something similar.

jpmorin
  • 6,008
  • 2
  • 28
  • 39
1

Please consider this answer: https://stackoverflow.com/a/27050497/1056679

I've tried to collect all possible methods of resolving dependencies in global scope before actual controllers are executed.

Community
  • 1
  • 1
Slava Fomin II
  • 26,865
  • 29
  • 124
  • 202