1

I am delving into Angularjs and got to the point where I am taking my application beyond the simple todo list stages.

A scenario I have, which must be common, is to have one controller that needs to be shared across multiple areas on my view.

In my case I have a profileController which I want to use to get the profile of the user from the server on each load.

When calling the loadUserProfile from within the profileController I saw that it was called 'n'-times (for the number of times I referenced the controller on the view), which is cool, so I changed the profileController to simply expose variables such as userProfile and isAuthenticated which simply references variables that I set in the $rootScope. These variables are set in a controller that is loaded once per page declared on my <body data-ng-controller="baseController as vm">, however this does not seem to work, and I am wondering what I am missing.

So it get's the data from the profileService, but when updating the $rootScope variables, it does not reflect it on my view.

Below is my baseController:

(function () {
    'use strict';

    var controllerId = 'baseController';
    angular.module('app.controllers').controller(controllerId, ['$location', 'common', 'authClientSvc', 'profileService', '$rootScope', baseController]);

    function baseController($location, common, authClientSvc, profileService, $rootScope) {
        var getLogFn = common.logger.getLogFn;
        var log = getLogFn(controllerId);
        var vm = this;

        $rootScope.isAuthenticated = false;
        $rootScope.userProfile = {
            email: '',
            name: '',
            surname: ''
        };


        activate();

        function activate() {
            var promises = [getUserProfile()];
            common.activateController([promises], controllerId)
                .then(function () { log('Activated Secure View'); });
        }

        function getUserProfile() {
            profileService.getProfile('a@a.com').then(function (data) {
                setTimeout(function () {
                    $rootScope.$apply(function () {
                        $rootScope.userProfile = data;
                        $rootScope.isAuthenticated = authClientSvc.isAuthenticated()
                    })
                }, 1000);
            });
        }
    }
})();

And my profileController where I expose the $rootScope variables below:

(function () {
    'use strict';

    var controllerId = 'profileController';
    angular.module('app')
        .controller(controllerId, ['common', 'authClientSvc', 'profileService', '$rootScope', profileController]);

    function profileController(common, authClientSvc, profileService, $rootScope) {
        var getLogFn = common.logger.getLogFn;
        var log = getLogFn(controllerId);

        var vm = this;

        vm.logoutUrl = '/';

        vm.isAuthenticated = $rootScope.isAuthenticated;
        vm.profile = $rootScope.userProfile;

        activate();

        function activate() {
            var promises = [];
            common.activateController(promises, controllerId)
                .then(function () { log('Activated Profile controller'); });
        }

        vm.logOut = function () {
            authClientSvc.logout();
        }
    }
})();

I am not sure what is wrong, because in Fiddler I can clearly see the data coming back, and when I debug it and put log messages in the baseController after if gets the profile, it gets back the right data, but for some reason it is not working on my elements. Below is a sample of how I use it on the view:

<div class="login-info" data-ng-controller="profileController as vm">
    <span ng-switch="vm.isAuthenticated">
        <a ng-switch-when="true" href="javascript:void(0);" id="show-shortcut" data-action="toggleShortcut">
            <img src="/Content/img/avatars/male.png" alt="me" class="online" />
            <span data-localize="{{vm.profile.name}}.{{vm.profile.surname}}">
                {{vm.profile.name}}.{{vm.profile.surname}}
            </span>
            <i class="fa fa-angle-down"></i>
        </a>
        <span ng-switch-when="false">
            <img src="/Content/img/avatars/male.png" alt="guest" class="online" />
            <span data-localize="Guest.user">
                Guest User
            </span>
        </span>
    </span>
</div>

Any help would be greatly appreciated, or even suggestions on how to achieve this in a better way.

Thanks.

Ryk
  • 3,072
  • 5
  • 27
  • 32

1 Answers1

13

According to Angular documentation:

When a Controller is attached to the DOM via the ng-controller directive, Angular will instantiate a new Controller object, using the specified Controller's constructor function. A new child scope will be available as an injectable parameter to the Controller's constructor function as $scope.

Meaning: Controllers are instantiated when the ng-controller directive is attached to the DOM. If you have two ng-controllers, then you will have two separate instances of ng-controller.

And

Do not use controllers to:

  • Share code or state across controllers — Use angular services instead.
Community
  • 1
  • 1
Michael Kang
  • 52,003
  • 16
  • 103
  • 135
  • 3
    I am sorry, but I don't see how this is even close to answering my question. – Ryk Sep 09 '14 at 11:28
  • 1
    Your approach of using rootScope to share data will work if you store a reference on root scope (like $rootScope.userInfo) and then assign userInfo to you controllers. This works because you are sharing the same userInfo reference across multiple controllers. But if you need to share data like this, a better practice approach is to use angular services. – Michael Kang Sep 09 '14 at 14:58
  • 1
    You did ask for suggestions on a *better* way, and I answered. You might want to change your question to say that you are *not* looking for a better way - you're question has thoroughly confused me – Michael Kang Sep 17 '14 at 00:36
  • Sorry for my late reply, I was away on leave. Anyway, when you do a bit of searching on my question you will quickly discover suggestions regarding patterns and anti-patterns, and some of them seem to be author bias rather than good practice, and since this is a new framework I am using, I want to learn the right way, hence my question, and there is nothing confusing about my question. Your answer is confusing. I will post my answer to what I ended up using in the next few days. You failed to cover any of the basic methods to share, and how to do it. ie service vs rootscope – Ryk Sep 28 '14 at 21:27