Update
Most of this is outdated now with the progression of angularFire. Check out this module for an updated version: https://github.com/firebase/angularFire-seed/blob/master/app/js/module.simpleLoginTools.js
It decorates ng-cloak
to work with simple login and provides some optimized helper methods as well as working with recent versions.
Old Post
Authenticating requires a round trip to the server. In an SPA, you don't generally reload the page during normal usage so this is really superfluous in most cases.
However, it's not difficult to solve with a moderate understanding of Angular. In fact, I taught this exact scenario as an example for writing directives in a recent workshop. Here's the gist I used, and here's an example app that uses the gist.
Note that if you try to clone the GitHub repo, you need to grab that particular tag (git checkout step3
) as the course was taught in steps.
For compliance with SO format, here's the contents of the gist. First the directive:
angular.module('waitForAuth', [])
/**
* A service that returns a promise object, which is resolved once angularFireAuth
* is initialized (i.e. it returns login, logout, or error)
*/
.service('waitForAuth', function($rootScope, $q, $timeout) {
var def = $q.defer(), subs = [];
subs.push($rootScope.$on('angularFireAuth:login', fn));
subs.push($rootScope.$on('angularFireAuth:logout', fn));
subs.push($rootScope.$on('angularFireAuth:error', fn));
function fn() {
for(var i=0; i < subs.length; i++) { subs[i](); }
$timeout(function() {
// force $scope.$apply to be re-run after login resolves
def.resolve();
});
}
return def.promise;
})
/**
* A directive that hides the element from view until waitForAuth resolves
*/
.directive('ngCloakAuth', function(waitForAuth) {
return {
restrict: 'A',
compile: function(el) {
console.log('waiting');
el.addClass('hide');
waitForAuth.then(function() {
el.removeClass('hide');
})
}
}
})
/**
* A directive that shows elements only when the given authentication state is in effect
*/
.directive('ngShowAuth', function($rootScope) {
var loginState;
return {
restrict: 'A',
compile: function(el, attr) {
var expState = attr.ngShowAuth;
function fn(newState) {
loginState = newState;
el.toggleClass('hide', loginState !== expState );
}
fn(null);
$rootScope.$on("angularFireAuth:login", function() { fn('login') });
$rootScope.$on("angularFireAuth:logout", function() { fn('logout') });
$rootScope.$on("angularFireAuth:error", function() { fn('error') });
}
}
});
And some example usages:
<style>
.hide { display: none; }
</style>
<script>
// include the waitForAuth module as a dependency
angular.module('myApp', ['waitForAuth'])
// you can use waitForAuth directly from your scripts
.controller('myController', function(waitForAuth) {
waitForAuth.then(function() {
/* do something after auth completes */
})
})
</script>
<!-- and you can use the directives in your views -->
<div ng-cloak-auth>Authentication has resolved.</div>
<div ng-show-auth="login">{{user.id}} is logged in</div>
<div ng-show-auth="logout">Logged out</div>
<div ng-show-auth="error">An error occurred during authentication</div>