AngularFire: how to set $location.path in onAuth()? - angularjs

I am building an angular+firebase app with user authentication (with angularfire 0.8).
I need to use onAuth() auth event handler, since I will provide multiple authentication paths, included social, and want to avoid code duplication. Inside onAuth callback, I need to reset location.path to '/'.
Usually everything works nicely, but, if app is loaded on an already authenticated session (<F5>, for example), on $scope.$apply() I get "Error: [$rootScope:inprog] $apply already in progress"
(if I don't use $scope.$apply(), location path is not applyed to scope, and no page change happens).
I suspect I make some stupid mistake, but can't identify it...
This is my workflow:
app.controller('AuthCtrl', function ($scope, $rootScope, User) {
var ref = new Firebase(MY_FIREBASE_URL);
$scope.init = function () {
$scope.users = [];
User.all.$bindTo($scope, 'users').then(function () {
console.info('$scope.users bound:', $scope.users);
});
};
$scope.login = function () {
ref.authWithPassword({
email: $scope.user.email,
password: $scope.user.password,
}, function(err) {
if (err) {
console.error('Error during authentication:', err);
}
});
};
ref.onAuth(function(authData) {
if (authData) {
console.info('Login success');
var $rootScope.currentUser = $scope.users[authData.uid];
$location.path('/');
$scope.$apply();
} else {
console.info('Logout success');
}
});
};
app.factory('User', function ($firebase) {
var ref = $firebase(new Firebase(MY_FIREBASE_URL + 'users'));
return {
all: ref.$asObject()
};
});

Just as a reference, I want to post the solution I found, and I'm currently adopting:
$scope.init = function () {
$scope.params = $routeParams;
$scope.debug = CFG.DEBUG;
$scope.lastBuildDate = lastBuildDate;
$scope.error = null;
$scope.info = null;
$scope.users = [];
User.all.$bindTo($scope, 'users').then(function () {
// watch authentication events
refAuth.onAuth(function(authData) {
$scope.auth(authData);
});
});
...
};
...
I.e., it was enough to move the watch on authentication events inside the callback to bindTo on users object from Firebase.

Related

How to return user data from Factory into a controller using Firebase

I have a factory which checks the authData of a user, using firebase. I wish to access the users details such as name, email etc, but I can't figure out how to get the snapshot data into an object which I can use. I'm new to Javascript.
this is my factory:
angular.module('.....')
.factory('UserDataService', function($q, $firebase, $firebaseAuth, FIREBASE_URL) {
var authData = {};
function authDataCallback(authData) {
if (authData) {
var ref = new Firebase(FIREBASE_URL + "/userProfiles/" + authData.uid);
ref.on("value", function(snapshot) {
var data = snapshot.val();
});
} else {
console.log("User is logged out");
}
}
// Register the callback to be fired every time auth state changes
var ref = new Firebase(FIREBASE_URL);
ref.onAuth(authDataCallback);
return authData;
});
2nd Attempt:
This time i am able to get the users details, but it won't save into the variable service and is returning to the controller as null. Here is my code:
var firebaseRef = new Firebase(FIREBASE_URL);
var authObj = $firebaseAuth(firebaseRef);
activate();
var service = {
userInfo: null
};
function activate() {
// Add listeners for authentication state changes
authObj.$onAuth(function(authData) {
if (authData) {
// Load the userInfo
loadUserInfo(authData);
} else {
// Destroy the userInfo Object if one exists
if (service.userInfo) {
service.userInfo.$destroy();
service.userInfo = null;
}
}
});
}
function loadUserInfo(authData) {
var userRef = firebaseRef.child('userProfiles').child(authData.uid);
var loadedInfo = $firebaseObject(userRef);
// console.log(loadedInfo);
loadedInfo.$loaded()
.then(function() {
service.userInfo = loadedInfo;
console.log(service.userInfo.name);
})
.catch(function(error) {
switch (error.code) {
case 'PERMISSION_DENIED':
alert('You don\'t have the permission to see that data.');
break;
default:
alert('Couldn\'t load the user info.');
}
});
}
return service;
You need to inject your service inside something (controller, service, filter or directive) and from the controller, call the service function.
.controller('myController', ['UserDataService', function($scope) {
$scope.userService = UserDataService;
}
Now you can call the function from your controller scope.
userService.authDataCallback()
You assign snapshot.val() to a local variable data. data is destroyed as soon as the function ends.
You need to assign it to the "outer" variable authData, which you can't because you have a function parameter with the same name.
Try it like this:
angular.module('.....')
.factory('UserDataService', function($q, $firebase, $firebaseAuth, FIREBASE_URL) {
var authData = {};
function authDataCallback(data) {
if (data) {
var ref = new Firebase(FIREBASE_URL + "/userProfiles/" + data.uid);
ref.on("value", function(snapshot) {
authData = snapshot.val();
//[see comment] var authData = snapshot.val();
});
} else {
console.log("User is logged out");
}
}
// Register the callback to be fired every time auth state changes
var ref = new Firebase(FIREBASE_URL);
ref.onAuth(authDataCallback);
return {
authData: authData
};
});
Also you should read up on the return types of service/factory in the docs. What the returned object of a factory does, is basically expose private variables/functions for other modules to access.
I suppose there is in var data an object.
You can access fields easily with dot .field. For example:
ref.once("value", function(snapshot) {
var data = snapshot.val();
// data is { "name": "Fred", "age": 53 }
// data.name === "Fred"
// data.age === 53
});
Depending on the data in a DataSnapshot, the val() method may return a
primitive (string, number, or boolean), an array, or an object. It may
also return null, indicating that the snapshot is empty and contains
no data.
Taken from:
https://www.firebase.com/docs/web/api/datasnapshot/val.html
I hope it helps.
-EDIT-
Use this format to get data in the controller:
var app = angular.module("sampleApp", ["firebase"]);
app.factory("Auth", ["$firebaseAuth",
function($firebaseAuth) {
var ref = new Firebase("https://docs-sandbox.firebaseio.com", "example3");
return $firebaseAuth(ref);
}
]);
app.controller("SampleCtrl", ["$scope", "Auth",
function($scope, Auth) {
$scope.auth = Auth;
// any time auth status updates, add the user data to scope
$scope.auth.$onAuth(function(authData) {
$scope.authData = authData;
});
}
]);
Assuming the snapshot is correct, the val() method turns it into an object.
Meaning data now contains the values you need. For example data.name.
The service should expose a function for this
function sendData() {
var deferred = $q.defer();
// Register the callback to be fired every time auth state changes
var ref = new Firebase(FIREBASE_URL);
ref.onAuth(function(snapshot) {
deferred.resolve(snapshot.val());
});
return deferred.promise;
}
Something like this
Cheers

It is safe to use $window.location.assign instead of $location.path()? | angularjs

I'm writing a service in AngularJS and I want that service do a redirection on a page I choose. I don't have a $scope in this so I'm using:
$window.location.assign('path');
as documented on w3c.
What I'm asking is if this is a safe usage or if I should use something different.
ps: those doesn't work:
$location.assign(); //assign is not a function
//
$location.path();
$scope.$apply(); //I don't have a $scope
Many thanks.
EDIT: added code (in socketio.listen('auth.loggedInSuccessfully', function(data) { I'm having the issue I described)
angular.module('frontendApp')
.factory('login', function ($window, socketio, $rootScope) {
// Service logic
// ...
var loginType = null;
// prepare socketio events
socketio.listen();
socketio.listen('auth.loggedInSuccessfully', function(data) {
console.log("Login verified by server!.. Redirecting...");
console.log("Login data received: " + JSON.stringify(data));
$rootScope.user = data.user;
$rootScope.$apply();
loginType = "facebook";
//console.log("$rootScope.user: " + JSON.stringify($rootScope.user.name));
//$location.path(destUrl); // THIS doesn't work.
$window.location.assign(data.destUrl); // this does!
});
socketio.listen('auth.loginFailed', function() {
console.log("Login failed!");
$rootScope.user = {}
});
socketio.listen('auth.logout', function() {
console.log("Logged out!");
$rootScope.user = {};
})
// Public API here
var api = {
fb: {
validateToken: function (access_token, destUrl) {
socketio.emit('fb.login', {
access_token: access_token,
destUrl: destUrl
});
console.log("Waiting server response...");
},[...]
};
return api;
});
Thanks for posting your code.
I believe in your example the location change is taking place in an event handler outside of AngularJS. Typically this requires the state changes to be wrapped in a $scope.$apply. Perhaps something like this:
socketio.listen('auth.loggedInSuccessfully', function(data) {
console.log("Login verified by server!.. Redirecting...");
console.log("Login data received: " + JSON.stringify(data));
loginType = "facebook";
$rootScope.$apply(function() {
$rootScope.user = data.user;
$location.path(destUrl);
});
});

FACTORY: get current user.id for Firebase Simple Login (Email / Password)

I am looking for a solid way to have the 'current user id' in all my controllers available.
Using: Firebase Simple Login : Email / Password Authentication
My ida: I need a 'Factory' wich I can inject into my controllers,
to have the 'current user id' always available.
I came up with this code:
app.factory('User', ['angularFire',
//Get Current UserID
function(angularFire){
console.log ('FACTORY: User');
var currentUser = {};
var ReturnStr = '';
var ref = new Firebase("https://myFIREBASE.firebaseio.com/");
var authClient = new FirebaseAuthClient(ref, function (err, user) {
if (err) {
ReturnStr = 'FACTORY: User Error: ' + err;
console.log (ReturnStr);
//var User = ReturnStr;
} else if (user) {
console.log ('FACTORY: User: Login successfully:');
console.log (user);
currentUser = user;
} else {
//console.log ('-----------User: Logged Out ---------------');
ReturnStr = 'FACTORY: Logged out: Redirect to Login';
console.log (ReturnStr);
window.location.href = "/login.php";
}
});
return currentUser;
}
]);
My simplest Controller looks like:
function ToDoCtrl($scope, User) {
$scope.MyUser = User;
$scope.MyUser.test = 'Test';
}
In HTML (angular partials) i have:
<h2>{{MyUser.id}}</h2>
<h2>{{MyUser.email}}</h2>
<h2>{{MyUser.provider}}</h2>
<h2>{{MyUser.test}}</h2>
=> id, email, provider are 'undefined'. In console I see the 'FACTORY: User: Login successfully:' with correct user - Object.
=> Asynchronous loading of data problem?
I have also experimented (without luck):
$timeout(function () {
currentUser = user;
}
Such a FACTORY would be very useful!
Thanks for a pointing me in the right direction!
Edit 1.1: Now, with $rootscope hack
=> Same effect - mycontroller is too fast - factory to slow.
app.factory('User', ['$rootScope', '$timeout', 'angularFire',
//Aktueller Benutzer auslesen
function($rootScope, $timeout, angularFire){
console.log ('FACTORY: User');
var currentUser = {};
var ReturnStr = '';
var ref = new Firebase("https://openpsychotherapy.firebaseio.com/");
var authClient = new FirebaseAuthClient(ref, function (err, user) {
if (err) {
ReturnStr = 'FACTORY: User Error: ' + err;
console.log (ReturnStr);
//var User = ReturnStr;
} else if (user) {
console.log ('FACTORY: User: Login successfully:');
//currentUser = user;
$timeout(function () {
ReturnStr = 'FACTORY: Inside timout';
console.log (ReturnStr);
currentUser = user;
console.log (currentUser);
$rootScope.myUser = user;
$rootScope.myUserID = user.id;
$rootScope.loggedIn = true;
$rootScope.$apply();
return currentUser;
});
} else {
//console.log ('-----------User: Logged Out ---------------');
ReturnStr = 'FACTORY: Logged out: Redirect to Login';
console.log (ReturnStr);
//var User = ReturnStr;
window.location.href = "/login.php";
}
});
return currentUser;
}
]);
TAHNKS for any helpful suggestions! Wonderin how others solve this!
So here is my solution to this exact problem. I am using Firebase, FirebaseAuthClient, and angularFire for my Angular app. I ran into the same situation for my login system where you cannot inject the $scope into the factory and therefore I came up with making a controller that used a factory for it's methods to retrieve, add, update, and delete things. And in the controller, I have my firebaseAuth stuff going on, the setting of the User values, and references whick I assign to the scope of that. Once the user is logged in, they are redirected to another location, at which point the app.js file takes over with a child controller when at that address location.
My login also uses localStorage, so logins will persist, you can refresh and not have to keep logging in, and you can change it to be cookies or sessionStorage easy enough.
This is going to need to be adapted for your needs specifically if you choose to use this method, it's quite complex no matter what, but this is very solid for me and I'm no longer needing to worry about firebaseAuth or angularFire stuff now that my factories are all setup for passing data back and forth. I'm just doing angularJS stuff mostly with directives. So here's my code.
NOTE: This will need modifying, and some things will be pseudo or open-ended for you to figure out for your needs.
AuthCtrl.js
'use strict';
angular.module('YOUR_APP', []).
controller('AuthCtrl', [
'$scope',
'$location',
'angularFire',
'fireFactory',
function AuthCtrl($scope, $location, angularFire, fireFactory) {
// FirebaseAuth callback
$scope.authCallback = function(error, user) {
if (error) {
console.log('error: ', error.code);
/*if (error.code === 'EXPIRED_TOKEN') {
$location.path('/');
}*/
} else if (user) {
console.log('Logged In', $scope);
// Store the auth token
localStorage.setItem('token', user.firebaseAuthToken);
$scope.isLoggedIn = true;
$scope.userId = user.id;
// Set the userRef and add user child refs once
$scope.userRef = fireFactory.firebaseRef('users').child(user.id);
$scope.userRef.once('value', function(data) {
// Set the userRef children if this is first login
var val = data.val();
var info = {
userId: user.id,
name: user.name
};
// Use snapshot value if not first login
if (val) {
info = val;
}
$scope.userRef.set(info); // set user child data once
});
$location.path('/user/' + $scope.userRef.name());
} else {
localStorage.clear();
$scope.isLoggedIn = false;
$location.path('/');
}
};
var authClient = new FirebaseAuthClient(fireFactory.firebaseRef('users'), $scope.authCallback);
$scope.login = function(provider) {
$scope.token = localStorage.getItem('token');
var options = {
'rememberMe': true
};
provider = 'twitter';
if ($scope.token) {
console.log('login with token', $scope.token);
fireFactory.firebaseRef('users').auth($scope.token, $scope.authCallback);
} else {
console.log('login with authClient');
authClient.login(provider, options);
}
};
$scope.logout = function() {
localStorage.clear();
authClient.logout();
$location.path('/');
};
}
]);
And now for the nice and simple yet quite reusable factory. You will need to set your Firebase path for your app for the baseUrl variable for it to work.
fireFactory.js
'use strict';
angular.module('YOUR_APP').
factory('fireFactory', [
function fireFactory() {
return {
firebaseRef: function(path) {
var baseUrl = 'https://YOUR_FIREBASE_PATH.firebaseio.com';
path = (path !== '') ? baseUrl + '/' + path : baseUrl;
return new Firebase(path);
}
};
}
]);
Info
You give the factory just a piece of the path reference such as 'users' which will be used as part of the full path ref to where you want to store your user data.
fireFactory.firebaseRef('users')
Once you have a reference set for a user, they won't need to be set again it will just use the existing data and .auth() to it. Additionally if there's an existing 'token' in localStorage it will use that to auth() the user too.
Otherwise, it will login() the user and pop open the Oauth windows for them to do so using whatever option you provide them.
I have spent a lot of time, many many hours days and yes even months searching for something better than this when it comes to Firebase/FirebaseAuthClient and angularFire. With the way the Firebase API and FireAuth API is, it's very annoying to make them play nicely with each other when using them with angularFire anyways. It's very frustrating but I've gotten past it finally.
If you want to check out the code for my app and see how I'm doing these things more completely, you can find it in this branch of my Webernote github repo.
Feel free to fork it, install and run it locally, or contribute to it even if you like. I could use some help myself :)
Hope this helps you!!
Here's the way I do it.
First of all I have my firebase auth service (I'm not using Angularfire) that calls off to Singly to handle logins. When the user status changes it $broadcasts an event.
p4pApp.factory('firebaseAuth', function($rootScope, singlyAuth) {
var auth = {},
FBref = new Firebase(p4pApp.FIREBASEPATH);
auth.login = function(service) {
singlyAuth.login(service);
};
auth.logout = function() {
FBref.unauth();
auth.user = null;
auth.broadcastAuthEvent();
};
auth.broadcastAuthEvent = function() {
$rootScope.$broadcast('authEvent');
};
auth.authWithToken = function(token) {
if (token !== undefined) {
FBref.auth(token, function(error, authData) {
if(!error) {
auth.user = authData.auth.account;
auth.broadcastAuthEvent();
} else {
auth.user = null;
auth.broadcastAuthEvent();
}
}, function(error) {
auth.user = null;
auth.broadcastAuthEvent();
});
}
};
return auth;
});
Then I have a 'top level' controller that looks after authorisation state.
var AuthCtrl = function($scope, firebaseAuth, singlyAuth, firebase, user) {
$scope.user = null;
$scope.logout = function() {
firebaseAuth.logout();
};
$scope.isLoggedIn = function() {
return !!$scope.user;
};
// src: Alex Vanston (https://coderwall.com/p/ngisma)
$scope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if (phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
$scope.$on('authEvent', function() {
$scope.safeApply(function() {
$scope.user = firebaseAuth.user;
});
user.setID(firebaseAuth.user);
if (firebaseAuth.user) {
firebase.fetch(['users', firebaseAuth.user], function(results) {
if (results) {
user.setData(results);
} else {
results = {};
results.createdAt = DateTimeStamp();
}
results.lastLogin = DateTimeStamp();
firebase.set('users', firebaseAuth.user, results);
});
} else {
user.clearData();
}
});
};
Finally, I use a dedicated user service to maintain user state. (It's still in development)
p4pApp.factory('user', function() {
var userService = {}, user={};
user.data = {};
userService.setID = function(id) {
user.id = id;
};
userService.getID = function() {
return user.id;
};
userService.setData = function(data) {
user.data = data || {};
};
userService.getData = function() {
return user.data;
};
userService.clearData = function() {
user.data = {};
};
userService.setDataField = function(field, data) {
user.data[field] = data;
};
userService.clearDataField = function(field) {
delete user.data[field];
};
userService.pushData = function(key, data) {
if (typeof(key) === 'string') {
user.data[key] = data;
} else {
_.reduce(key, function(obj, child, index, list) {
obj[child] = obj[child] || {};
if (index == list.length-1) {
obj[child] = data;
}
return obj[child];
}, user.data);
}
};
userService.deleteData = function(key) {
if (typeof(key) === 'string') {
delete user.data[key];
} else {
_.reduce(key, function(obj, child, index, list) {
obj[child] = obj[child] || {};
if (index == list.length-1) {
delete obj[child];
return;
}
return obj[child];
}, user.data);
}
};
return userService;
});
This is most probably due to async nature of the call. To fix it you would have to
Inject $scope into the factory function (similar to angularFire dependency)
Use $scope.$apply() after the assigment currentUser = user;
Another solution that works for me:
account.service.js
(function() {
'use strict';
angular
.module('app.account')
.factory('Account', Account);
Account.$inject = [
'$firebaseAuth',
'$firebaseObject'
];
/* #ngInject */
function Account(
$firebaseAuth,
$firebaseObject,
) {
var firebaseRef = new Firebase('https://<<-- MY_FIREBASE -->>.firebaseio.com');
var authObj = $firebaseAuth(firebaseRef);
var service = {
userInfo: null
};
activate();
return service;
////////////////
function activate() {
// Add listeners for authentication state changes
authObj.$onAuth(function(authData) {
if (authData) {
// Load the userInfo
loadUserInfo(authData);
} else {
// Destroy the userInfo Object if one exists
if (service.userInfo) {
service.userInfo.$destroy();
service.userInfo = null;
}
}
});
}
function loadUserInfo(authData) {
var userRef = firebaseRef.child('users').child(authData.uid);
var loadedInfo = $firebaseObject(userRef);
loadedInfo.$loaded()
.then(function() {
service.userInfo = loadedInfo;
})
.catch(function(error) {
switch (error.code) {
case 'PERMISSION_DENIED':
alert('You don\'t have the permission to see that data.');
break;
default:
alert('Couldn\'t load the user info.');
}
});
}
}
})();
some-component.controller.js
(function() {
'use strict';
angular
.module('app')
.controller('SomeController', SomeController);
SomeController.$inject = [
'Account'
];
/* #ngInject */
function SomeController(
Account
) {
var vm = this;
vm.userInfo = userInfo;
////////////////
function userInfo() {
return Account.userInfo;
}
...
}
})();
some-component.html
...
<div class="user-id">
{{vm.userInfo().id}}
<div>
...

How to handle Firebase auth in single page app

I am using firebase simple login auth with angularjs and I want to create a single page app.
Before this, I have tried using service, main controller to handle it but I don't think it is good enough because I have to call FirebaseAuthClient() every time there is a route.
I also try to put FirebaseAuthClient() in angularjs .run() which initialize when app is start.
But it won't work when there is a route, I think it is because not a full page load.
Ok,
And here is what I want,
except login page, every route (pages) are required login.
A global FirebaseAuthClient() checking on every route so I don't need to call it again.
A global user which return from FirebaseAuthClient()
I'm not sure I understand. You only need to initialize FirebaseAuthClient and all login() once in your entire app. It's a singleton, and your auth credentials apply to any Firebase operations you perform.
What makes you think that this is not the case? What sorts of errors are you seeing?
Here is what I was using before moving auth over to Singly. Maybe it helps?
p4pApp.factory('firebaseAuth', function($rootScope) {
var auth = {},
FBref = new Firebase(p4pApp.FIREBASEPATH);
auth.broadcastAuthEvent = function() {
$rootScope.$broadcast('authEvent');
};
auth.client = new FirebaseAuthClient(FBref, function(error, user) {
if (error) {
} else if (user) {
auth.user = user;
auth.broadcastAuthEvent();
} else {
auth.user = null;
auth.broadcastAuthEvent();
}
});
auth.login = function() {
this.client.login('facebook');
};
auth.logout = function() {
this.client.logout();
};
return auth;
});
The AuthCtrl is common to all/most of my pages.
var AuthCtrl = function($scope, firebaseAuth) {
$scope.login = function() {
firebaseAuth.login();
};
$scope.logout = function() {
firebaseAuth.logout();
};
$scope.isLoggedIn = function() {
return !!$scope.user;
};
// src: Alex Vanston (https://coderwall.com/p/ngisma)
$scope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if (phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
$scope.$on('authEvent', function() {
$scope.safeApply(function() {
$scope.user = firebaseAuth.user;
});
});
};
From within the AuthCtrl you can just call isLoggedIn() to see if the user is logged in or not.

angularjs with firebase auth share service

Halo all,
I want to use angularjs with firebase simple login (facebook). But I have no idea how to
create the auth share service.
What I want to do is
create a authentication service
use this auth service to check if user loggedin in every controllers
controllers will do the $location if user loggedin/not-login
I also new to angularjs but I don't know which services should I use in this situation.
service or factory?
How can I put the below code in angular service then tell each controller if user logged in or not?
var firebaseRef = new Firebase("https://test.firebaseio.com");
var auth = new FirebaseAuthClient(firebaseRef, function(error, user) {
if (user) {
console.log(user);
} else if (error) {
console.log(error);
} else {
console.log('user not login');
}
});
Here is what i'm guessing, return user value from authService so in controllers if authService.user exists then redirect to loggedin page otherwise show login dialog with a
login button to call the following code
authService.login('facebook');
Let me know if I can do like this, or there is a better way?
Here is what I'm using so far...
I haven't implemented the redirecting yet but the rest works.
p4pApp.factory('firebaseAuth', function($rootScope) {
var auth = {},
FBref = new Firebase(p4pApp.FIREBASEPATH);
auth.broadcastAuthEvent = function() {
$rootScope.$broadcast('authEvent');
};
auth.client = new FirebaseAuthClient(FBref, function(error, user) {
if (error) {
} else if (user) {
auth.user = user;
auth.broadcastAuthEvent();
} else {
auth.user = null;
auth.broadcastAuthEvent();
}
});
auth.login = function() {
this.client.login('facebook');
};
auth.logout = function() {
this.client.logout();
};
return auth;
});
The AuthCtrl is common to all/most of my pages.
var AuthCtrl = function($scope, firebaseAuth) {
$scope.login = function() {
firebaseAuth.login();
};
$scope.logout = function() {
firebaseAuth.logout();
};
$scope.isLoggedIn = function() {
return !!$scope.user;
};
// src: Alex Vanston (https://coderwall.com/p/ngisma)
$scope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if (phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
$scope.$on('authEvent', function() {
$scope.safeApply(function() {
$scope.user = firebaseAuth.user;
});
});
};
Regarding factory vs. service, there was a good blog post explaining how to approach the choice that I recommend reading: http://iffycan.blogspot.com/2013/05/angular-service-or-factory.html
In terms of doing authentication, your general approach of assigning signed in state to a variable in a service seems alright. We're thinking about doing a deeper integration with Angular for authentication, but for now this seems like a reasonable approach.

Resources