0

I am using angularfire with the yeoman generator and have a working logout function in my account controller:

  $scope.logout = function() { Auth.$unauth(); };

Where Auth is:

(function() {
'use strict';
angular.module('firebase.auth', ['firebase', 'firebase.ref'])

  .factory('Auth', function($firebaseAuth, Ref) {
    return $firebaseAuth(Ref);
  });
})();

That part works great. I would like to make a logout button in the nav bar but since that is in a different scope, I need to make an emitter in my nav controller:

$scope.logout = $scope.$emit('loggedOut'); 

In my account controller, I listen for emitted signal. Both of these ways do not work:

$scope.$on('loggedOut', function() { Auth.$unauth(); });
$scope.$on('loggedOut', $scope.logout );

Can anyone tell me what I am missing? Thanks!

EDIT- I updated my code but I still have issues:

angular.module('rutileApp')
  .controller('AccountCtrl', function ($scope, user, Auth, Ref, $firebaseObject, $timeout) {
    $scope.logout = function() { Auth.$unauth(); };

    $scope.$on('loggedOut', function(event, msg) {
      $scope.logout();
    });
});

angular.module('rutileApp')
  .controller('NavCtrl', function ($scope, $rootScope) {
    $scope.sendLogout = function() {
      $rootScope.$broadcast('loggedOut', {msg: 'logging out'});
    }

  });

I cannot see the broadcasted signal in the AccountCtrl scope even if it is just to console.log something so it isn't a problem with the logout function.

Coherent
  • 1,933
  • 5
  • 24
  • 33

4 Answers4

1

EDIT: I kept my original answer down below, but here is an updated plunker that demonstrates calling a logout function by broadcast (but you must have an instance of that controller already loaded in order to access it). I also show how you can put the logout function inside a factory, which you can then inject into your controller and call from anywhere, and there is no need to have any particular controller instantiated.

Also, just looking at your code, I don't see why you can't call your Auth service directly - just inject Auth into your NavCtrl and add the logout function there like you did in the AccountCtrl : $scope.logout = function() {Auth.$unauth();}

It's the same thing..no reason to call the AccountCtrl method when you can access that factory from anywhere.

Plunker

Factory:

angular.module('rutileApp')
  .factory('accountFactory', function() {
    return {
      logout: function() {
        console.log('called logout from somewhere')
        return 'called logout from somewhere';
      }

    }
  })

You should do $rootScope.broadcast('logout', msg);

As others mentioned - $emit fires events from child scopes upwards to parent scopes. $broadcast fires events downwards to child scopes. But in the case of sibling scopes, neither of these will work. Every scope is a child of $rootScope, and we can access $rootScope from anywhere by injecting it into our controller. Therefore you want to fire your event down from $rootScope to child scopes.

Plunker

app.controller('MainCtrl', function($scope) {
  $scope.$on('logout', function(event, msg) {
    $scope.msg = msg.msg
    console.log(msg.msg);
  })
});
app.controller('OtherCtrl', function($scope, $rootScope) {
  $scope.sendLogout = function() {
    $rootScope.$broadcast('logout', {msg: 'logging out now!'});
  }
});
tpie
  • 6,021
  • 3
  • 22
  • 41
  • Thanks for the response! When I click the button, I can get a console.log in my $scope.sendLogout function to fire off but I cannot see the console.log fire in my MainCtrl. Consequentially, I don't log off. Is there something else to watch for? – Coherent May 07 '15 at 05:51
  • 1
    you are calling the logout method inside the scope.$on ? – tpie May 07 '15 at 05:53
  • It's probably because you don't have the AccountCtrl instantiated. Truth be told, you should have your logout function in a factory anyway. Then you could just call it without doing $broadcast. See here, I have it working using your code: http://plnkr.co/edit/a0gnFxxQiXTkueXsePxJ?p=preview – tpie May 07 '15 at 06:08
0

If the nav controller and the account controller don't have a parent-child $scope relationship (if the tags on which the controllers are instantiated aren't nested), the $scope.$emit('event') will never work.

In Angular, the events can be emitted both with $emit (that dispatches the event to the parent scopes of the emitter) and with $broadcast (that dispatches the event to the child scopes of the emitter).

A workaround to your problem, is using $rootScope.$broadcast that will dispatch the event to all the scopes of the application. Not elegant but it works!

Woznihack
  • 36
  • 3
0

Most probably this is a scope hierarchy issue because of which the event handlers are not been called.

In Angular $emit, sends the events upwards and $broadcast downwards the scope hierarchy.

The nav controller scope has to be child scope of account controller for $emit to work.

The better option would be to use $rootScope.$broadcast which would be received by every controller scope.

Chandermani
  • 42,589
  • 12
  • 85
  • 88
0

$emit only bubbles up to the parent scope, so it's not going to work unless your account controller is a parent to your nav controller. You can use $broadcast if it is a child. If there is no relation, it has to be on the $rootScope. Longer answer: Working with $scope.$emit and $scope.$on

Community
  • 1
  • 1
bachism
  • 41
  • 1