Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular .controller() runs before .run() AngularJS

Tags:

angularjs

I have an ajax call inside the .run() that loads a variable into the $rootScope That variable is needed in the controller associated with a view. Sometimes on refresh (F5) by the time the .controller is loading there is nothing inside $rootScope.SuperCategories.

sampleApp.factory('SuperCategoryService', ['$http', '$q', '$rootScope', function ($http, $q, $rootScope){

    var SuperCategoryService =  {};
    SuperCategoryService.SuperCategories = $rootScope.SuperCategories;
    alert ($rootScope.SuperCategories);
    return SuperCategoryService;

}]);



sampleApp.run(function($rootScope, $q, $http) {

    var req = {
        method: 'POST',
        url: 'SuperCategoryData.txt',
        //url: 'http://localhost/cgi-bin/superCategory.pl',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' }//,
        //data: { action: 'GET' }
    };


    $rootScope.SuperCategories = [];

    $rootScope.GetSuperCategories = function () {

        var defer = $q.defer();
        $http(screq).then(function(response) {
            $rootScope.SuperCategories = response.data;
            //alert ($rootScope.SuperCategories);
            defer.resolve($rootScope.SuperCategories);
        }, function(error) {
            defer.reject("Some error");
        });
        return defer.promise;
    }

    $rootScope.GetSuperCategories();


});

How to fix this bug.

like image 919
Devesh Agrawal Avatar asked Apr 06 '15 17:04

Devesh Agrawal


People also ask

Where does the application run in AngularJS?

The application runs inside the <div>. The ng-controller="myCtrl" attribute is an AngularJS directive. It defines a controller. The myCtrl function is a JavaScript function. AngularJS will invoke the controller with a $scope object. In AngularJS, $scope is the application object (the owner of application variables and functions).

What is ng-controller in angular?

AngularJS Controllers AngularJS applications are controlled by controllers. The ng-controller directive defines the application controller. A controller is a JavaScript Object, created by a standard JavaScript object constructor.

Which Directive defines the application controller in AngularJS?

The ng-controller directive defines the application controller. A controller is a JavaScript Object, created by a standard JavaScript object constructor. The AngularJS application is defined by ng-app="myApp". The application runs inside the <div>.

How to call a function on page load in AngularJS?

Calling a function or initializing a single value on page load in AngularJS is quite easy. AngularJS provides us with a dedicated directive for this specific task. It’s the ng-init directive. Syntax: <element ng-init="function()"> Contents... </element> Example 1: In this example we will call a function to initialize a variable on page load. <


2 Answers

NB: this is not directly answer to you question. I've just tried to rewrite your code a little bit in a way to utilize promises and factory more common way, may be it will give you some ideas what can be improved to make the async code work more predictably.

Controller calls factory to get the data, and when Promise is resolved you have you data in $rootScope.SuperCategories

 sampleApp.factory('SuperCategoryService', ['$http', '$q', function ($http, $q){

    var req = {
        method: 'POST',
        url: 'SuperCategoryData.txt',
        //url: 'http://localhost/cgi-bin/superCategory.pl',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' }//,
        //data: { action: 'GET' }
    };

    var SuperCategoryService =  {};

    SuperCategoryService.SuperCategories = function () {

        var defer = $q.defer();
        $http(screq).success(function(response) {
            defer.resolve(response);
        });
        return defer.promise;
    }


    return SuperCategoryService;

}]);



sampleApp.controller('myController', ['$scope', 'SuperCategoryService', function($scope, SuperCategoryService) {

   SuperCategoryService.SuperCategories().then(function(data){
             $rootScope.SuperCategories = data;
        });


});
like image 165
shershen Avatar answered Oct 13 '22 21:10

shershen


In such cases you could something like this.

sampleApp.run(function($rootScope, $q, $http) {
    ...  
    // once the promise is resolved and SuperCategories are filled  
    $rootScope.$emit('init');
});


sampleApp.controller('AppCtrl', function ($rootScope) {

    function init() {
        ...
    }

    var unbindHandler = $rootScope.$on('init', function () {
        init();
        unbindHandler();
    });

});

You can do similar thing with $rootScope.$watch, but since the watcher has initial launch, it isn't a good fit for one-time listeners.

Anyway, top-level controller is a better place for all initial work on the scope, there's no need to do something like this in run().

How to fix this bug.

It is not a bug but the expected behaviour of asynchronous workflow. You should never rely on delays when resolving promises, unless app gives you an opportunity to control its phases (and Angular doesn't give one).

Angular app runs in such order:

  • module config
  • module run
  • directive factory function
  • directive compile
  • directive controller (ng-controller is also a directive, right?)
  • directive prelink
  • directive (post)link
  • route resolve
  • route controller

Let's assume we monkey-patched $controllerProvider, so controllers will humbly wait for 'controllersReadySetGo' event from run() that may happen someday. Now guess what will happen with e.g. directive pre/postlinks that seriously rely on having a controller instance.

like image 29
Estus Flask Avatar answered Oct 13 '22 22:10

Estus Flask