Is it good to have main controller in Angular?

All we need is an easy explanation of the problem, so here it is.

I dont know if this is a good practice… I have a controller defined in route config but because my HomeCtrl is in ng-if statement he cannot listen for loginSuccess so I made MainCtrl which listens for loginSuccess and reacts appropriately. This code works just fine but this smells like a hack to me. Should I remove MainCtrl and make it a service? If so some example would be really great.

Index.html

<body ng-app="myApp" ng-controller="MainCtrl">
    <div ng-if="!isLoged()">
      <signIn></signIn>
    </div>
    <div ng-if="isLoged()">
      <div class="header">
          <div class="nav">
            <ul>
                <a href="/" rel="nofollow noreferrer noopener"><li class="book">navItem</li></a>
            </ul>
          </div>
      </div>
      <div class="container" ng-view=""></div>
    </div>
</body>

App.js

    angular.module('myApp', [])
      .config(function ($routeProvider) {
        $routeProvider
          .when('/', {
            templateUrl: 'views/main.html',
            controller: 'HomeCtrl'
          })
          .otherwise({
            redirectTo: '/'
          });
      })
  .controller('MainCtrl', function ($scope) {
    $scope.user = false;
    $scope.isLoged = function(){
         if($scope.user){
          return true;
         }else{
          return false;
         }
    }
    $scope.$on('event:loginSuccess', function(ev, user) {
       $scope.user = user;
       $scope.$apply();
    });
  })
  .controller('HomeCtrl', function ($scope, $location) {
  //this is home controller  
  })
  .directive('signIn', function () {
    return {
      restrict: 'E',
      link: function (scope, element, attrs) {
        //go to the server and then call signinCallback();
      }
    };
  })
  .run(['$window','$rootScope','$log',function($window, $rootScope){
    $window.signinCallback = function (res) {
      if(res){
        $rootScope.$broadcast('event:loginSuccess', res);
      }
      else{
        $rootScope.$broadcast('loginFailure',res);
      }
    }; 
  }]);

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

I start all of my Angular projects with:

<html ng-app="appName" ng-controller="appNameCtrl">

The use of a “global” controller may not be necessary, but it is always nice to have it around when a need arises. For example, I use it in my CMS to set a binding that initiates the loading of everything else – so all the sub controllers are loaded because of it. That isn’t violating separation of concerns because the global controller’s concern IS to facilitate the loading of other controllers.

That said, just be sure to keep things as modular/separated and reusable as possible. If your controllers rely on the global controller’s existence in order to function, then there is an issue.

Method 2

In my opinion angular js’ power comes with separating out clearly the different controllers directives, services, resources etc. Ideally controllers are linked to templates or partials and are used to update the front end and make calls to services or resources. The sooner you start making these separations the sooner you will start making clean and scalable apps that other developers can quickly make sense of. For app structure I would highly recommend you look into either of these two tools:

Lineman.js

and

Yeomann

The lineman site actually has a really good round up of how the two differ, if you scroll down.

In your scenario there are many ways to link controllers or make function calls that are in different scopes. You can either create a service that injects to your controllers or you can use $emit and $on to set up notifications in the app eg:

In controller A

$rootScope.$on('myNotifier:call', function() {
        myFunction();
    });

And in Controller B or any other controller you could call myFunction() with:

$scope.$emit('newPatientModal:close');

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply