Peter
Peter

Reputation: 1290

$rootscope.$broadcast and $scope.$on with parent- and multiple child controllers

In my index.html file i got a appController that is like a main controller that has to load some basic settings in the $rootScope so i can use these settings in the child controllers (data-ui-view = ui-router plugin).

<body ng-controller="appController">

    <div data-ui-view></div>

</body>

In the appController i'm using a service (appService) where i get data from the database and put a fraction of that data in a $rootScope property formData

appService.formData()
.then(function(data) {
    $rootScope.formData = data[0].num;
    if ($rootScope.formData) {
        $rootScope.$broadcast('afterFormDataLoaded');
    }
}) 

It's very important that other (child) controllers don't run before the $rootScope.formData is filled with the actual data. So to accomplish that i use $rootScope.$broadcastin the parent controller and:

$scope.$on('afterFormDataLoaded', function () {
    // the code
})

$scope.$on in the child controllers.

This works! My child controller is only running after the $broadcast in the main controller is set to afterFormDataLoaded.

But i'm having problems when i change the view and i navigate from one child (view & controller) to another. It's clear for me that i will have problems with that $broadcast method because $broadcast run one time when i load/refresh the page and not when i change the view. So $scope.$on will not be triggered when i change the view.

what is the proper and most plausibly way to let all my child controllers wait until my parent asynchronous function is succesfully done and $rootScope.formData is true?

Upvotes: 1

Views: 503

Answers (2)

Walfrat
Walfrat

Reputation: 5353

In ui-router you can add a resolve parameter to state declaration (https://github.com/angular-ui/ui-router/wiki#resolve). In order to have it working you have to store somewhere the promise until is resolved.

Here's is an example

angular.run(['$rootScope', '$q', function($rootScope, $q){
    var defer = $q.defer();
   var dataPromise = defer.promise;
   $rootScope.resolveDataPromise = function(data){
       defer.resolve(data);
   } 
}]);

angular.config(['$stateProvider', function($stateProvider){
   $stateProvider.state({
       resolve:{
           myData:['$rootScope', function($rootScope){
              return $rootScope.dataPromise;
           }]
       }
   });
}]);

appService.formData().then(function(data) {
    if(data[0].num){
        $rootScope.resolveDataPromise(data[0].num);
    }
}) 

Note : to get the data of the resolve you can just inject it in your controller, the key of the resolve object will be the name : myData here.

You can either define it in all state you need it or in a parent of all the state, this will work.

Upvotes: 1

Aides
Aides

Reputation: 3673

You could reference $rootScope on the respective controller and in a start function read if $rootScope.formData is filled, and if not register your listener.

Also if you are using ui-router resolve might do exactly what you want.

Upvotes: 0

Related Questions