2

Been playing around with firebase and angularjs and just trying to put some little things together. I have the auth working now in a controller with this function called on the sign in button click:

$scope.signin = function(){
        var user1 = $scope.cred.user;
        var pass1 = $scope.cred.password;

        var ref = new Firebase("https://kingpinapp.firebaseio.com");
        var auth = new FirebaseAuthClient(ref, function(error, user) {
            if (user) {
                // user authenticated with Firebase
                console.log(user);


            } else if (error) {
                 // an error occurred authenticating the user
                 console.log(error);

                } else {
                // user is logged out
            }   
        });
        auth.login('password', {
            email: user1,
            password: pass1,
            rememberMe: false
        });
        console.log("tracer");
}

Now this is great and works fine. But it seems to work in a async manner for example my console.log("tracer") returns before the user object of the auth.login. I know I probably need to work with promises to get this done and tried doing the following:

var defer = $q.defer();
defer.auth
.then(function() {
    auth.login('password', {
        email: user1,
        password: pass1,
        rememberMe: false
    });
})
.then(function() {
    console.log("tracer");
})

But i'm receiving a $q is not defined after declaring it in the controller module. So what I'm trying to do is

  1. check if the user is logged in.
  2. wait till I receive a yes/no
  3. if not logged in. use auth.login
  4. else user user logged in do some other things

I thought of putting the auth.login function in the else of the variable auth but that doesn't seem like it would work. Just trying to figure out the proper logic in understanding how to get this to work.

asiammyself
  • 219
  • 3
  • 12
  • new Firebase("https://kingpinapp.firebaseio.com") automatically returns a promise which is resolved when you recieve data from server so there is no need manually to use $q – Ajay Beniwal May 07 '13 at 19:33
  • Ok so say we run FirebaseAuthClient which checks if the user is logged in. If there not logged in I want to run the auth.login function. Should I put auth.login in my else statement? I get an error in the console trying that. – asiammyself May 07 '13 at 20:03
  • @asiammyself FirebaseAuthClient() does not check if the user is logged in! It only sets up a callback that is run whenever a user's authentication state changes (see: https://www.firebase.com/docs/security/simple-login-overview.html). In other words, nothing happens until you call `auth.login()`. Your code looks correct, you just need to put your "user logged in do some other things" code in the `if (user) { ... }` block. – bennlich May 07 '13 at 21:39
  • @asianmyself As an aside, the reason $q wasn't working is probably because you forgot to inject it in your controller. What Ajay said isn't really true, as far as I know, but he's right that you don't need to use $q if you don't want to. – bennlich May 07 '13 at 21:46
  • So if FirebaseAuthClient is run whenever there is a user authentication change. If there are multiple controllers, instead of putting one in each controller would the proper way of doing it be putting the FirebaseAuthClient in a factory? – asiammyself May 07 '13 at 23:02
  • @asianmyself Yes (ish). You should put FirebaseAuthClient in a _Service_. A _Factory_ is one way to instantiate a _Service_. See this post on the minor (but confusing!) difference: http://stackoverflow.com/questions/15666048/angular-js-service-vs-provide-vs-factory/15666049#15666049. – bennlich May 08 '13 at 23:44
  • I was somewhat wrong about FirebaseAuthClient--it will automatically log in a user who has logged in previously. The callback might be run immediately, before any calls to .login(). See my answer below. – bennlich May 10 '13 at 19:36
  • Check out the answer for this that I posted here: http://stackoverflow.com/questions/17259556/factory-get-current-user-id-for-firebase-simple-login-email-password/17271802#17271802 – jaredwilli Jun 24 '13 at 09:14

3 Answers3

6

You don't want to have a FirebaseAuthClient per controller, but you do want to alert all of your controllers when a user's auth state changes.

FirebaseAuthClient will take care of session storage for you. You just need to hide your sign in screen/button once a user is successfully signed in.

Try something like this:

.service('myAuthService', ["$rootScope", function($rootScope) {
    var ref = new Firebase("https://kingpinapp.firebaseio.com");
    this.auth = new FirebaseAuthClient(ref, function(error, user) {
        if (user) {
            $rootScope.$emit("login", user);
        }
        else if (error) {
            $rootScope.$emit("loginError", error);
        }
        else {
            $rootScope.$emit("logout");
        }   
    });
}])
.controller('myCtrl', ["$scope", "$rootScope", "myAuthService", function($scope, $rootScope, myAuthService) {
    $scope.signin = function() {
        var user1 = $scope.cred.user;
        var pass1 = $scope.cred.password;

        myAuthService.auth.login('password', {
            email: user1,
            password: pass1,
            rememberMe: false
        });
    }
    // listen for user auth events
    $rootScope.$on("login", function(event, user) {
        // do login things
        $scope.user = user;
    })
    $rootScope.$on("loginError", function(event, error) {
        // tell the user about the error
    })
    $rootScope.$on("logout", function(event) {
        // do logout things
    })
}])
<button ng-show="user" ng-click="signin()">Sign in</button>
bennlich
  • 1,207
  • 10
  • 21
  • Would be much appreciated if you could provide bottom line simplest working example - thanks in advance – Iladarsda Nov 06 '13 at 21:04
2

Make sure you are including $q as a dependency in your controller. In the simple case:

function MyController($scope, $q, angularFire) {
  $scope.signin = ...
}

Or if you're using the "proper" module syntax:

angular.module("MyModule", ["firebase"]).
controller("MyController", ["$scope", "$q", "angularFire", function($scope, $q, aF) {
  $scope.signin = ...
}]);

Learn more about angular dependency injection here: http://docs.angularjs.org/guide/di, and take a look at https://gist.github.com/sbrekken/5151751 for an example of Firebase auth using deferred.

Anant
  • 7,408
  • 1
  • 30
  • 30
  • 1
    I'm trying to implement the above but I'm using a $routeProvider. The service is getting fired before the controller. I've had a look at the deferred method linked but I can't figure out where that code would be implemented. Is it in the service? – defmech May 28 '13 at 20:03
0

I've posted the answer to this question already here FACTORY: get current user.id for Firebase Simple Login (Email / Password)

It's a pretty solid solution to this problem and may be just what you're looking for.

Community
  • 1
  • 1
jaredwilli
  • 11,762
  • 6
  • 42
  • 41