-
-
Save katowulf/7328023 to your computer and use it in GitHub Desktop.
| 'use strict'; | |
| /** | |
| * This module monitors angularFire's authentication and performs actions based on authentication state. | |
| * directives/directive.ngcloakauth.js depends on this file | |
| * | |
| * Modify ng-cloak to hide content until FirebaseSimpleLogin resolves. Also | |
| * provides ng-show-auth methods for displaying content only when certain login | |
| * states are active. | |
| * | |
| * Just like other ng-cloak ops, this works best if you put the following into your CSS: | |
| [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { | |
| display: none !important; | |
| } | |
| * | |
| * See usage examples here: https://gist.github.com/katowulf/7328023 | |
| */ | |
| angular.module('simpleLoginTools', []) | |
| /** | |
| * A service that returns a promise object, which is resolved once $firebaseSimpleLogin | |
| * is initialized. | |
| * | |
| * <code> | |
| * function(waitForAuth) { | |
| * waitForAuth.then(function() { | |
| * console.log('auth initialized'); | |
| * }); | |
| * } | |
| * </code> | |
| */ | |
| .service('waitForAuth', function($rootScope, $q, $timeout) { | |
| function fn(err) { | |
| if($rootScope.auth) { | |
| $rootScope.auth.error = err instanceof Error? err.toString() : null; | |
| } | |
| for(var i=0; i < subs.length; i++) { subs[i](); } | |
| $timeout(function() { | |
| // force $scope.$apply to be re-run after login resolves | |
| def.resolve(); | |
| }); | |
| } | |
| var def = $q.defer(), subs = []; | |
| subs.push($rootScope.$on('$firebaseSimpleLogin:login', fn)); | |
| subs.push($rootScope.$on('$firebaseSimpleLogin:logout', fn)); | |
| subs.push($rootScope.$on('$firebaseSimpleLogin:error', fn)); | |
| return def.promise; | |
| }) | |
| /** | |
| * A directive that wraps ng-cloak so that, instead of simply waiting for Angular to compile, it waits until | |
| * waitForAuth resolves (in other words, until the user's login status resolves via Firebase) | |
| * | |
| * <code> | |
| * <div ng-cloak>Authentication has resolved.</div> | |
| * </code> | |
| */ | |
| .config(function($provide) { | |
| // adapt ng-cloak to wait for auth before it does its magic | |
| $provide.decorator('ngCloakDirective', function($delegate, waitForAuth) { | |
| var directive = $delegate[0]; | |
| // make a copy of the old directive | |
| var _compile = directive.compile; | |
| directive.compile = function(element, attr) { | |
| waitForAuth.then(function() { | |
| // after auth, run the original ng-cloak directive | |
| _compile.call(directive, element, attr); | |
| }); | |
| }; | |
| // return the modified directive | |
| return $delegate; | |
| }); | |
| }) | |
| /** | |
| * A directive that shows elements only when the given authentication state is in effect | |
| * | |
| * <code> | |
| * <div ng-show-auth="login">{{auth.user.id}} is logged in</div> | |
| * <div ng-show-auth="logout">Logged out</div> | |
| * <div ng-show-auth="error">An error occurred: {{auth.error}}</div> | |
| * <div ng-show-auth="logout,error">This appears for logout or for error condition!</div> | |
| * </code> | |
| */ | |
| .directive('ngShowAuth', function ($rootScope) { | |
| var loginState = 'logout'; | |
| $rootScope.$on('$firebaseSimpleLogin:login', function() { loginState = 'login'; }); | |
| $rootScope.$on('$firebaseSimpleLogin:logout', function() { loginState = 'logout'; }); | |
| $rootScope.$on('$firebaseSimpleLogin:error', function() { loginState = 'error'; }); | |
| function getExpectedState(scope, attr) { | |
| var expState = scope.$eval(attr); | |
| if( typeof(expState) !== 'string' && !angular.isArray(expState) ) { | |
| expState = attr; | |
| } | |
| if( typeof(expState) === 'string' ) { | |
| expState = expState.split(','); | |
| } | |
| return expState; | |
| } | |
| function inList(needle, list) { | |
| var res = false; | |
| angular.forEach(list, function(x) { | |
| if( x === needle ) { | |
| res = true; | |
| return true; | |
| } | |
| return false; | |
| }); | |
| return res; | |
| } | |
| function assertValidStates(states) { | |
| if( !states.length ) { | |
| throw new Error('ng-show-auth directive must be login, logout, or error (you may use a comma-separated list)'); | |
| } | |
| angular.forEach(states, function(s) { | |
| if( !inList(s, ['login', 'logout', 'error']) ) { | |
| throw new Error('Invalid state "'+s+'" for ng-show-auth directive, must be one of login, logout, or error'); | |
| } | |
| }); | |
| return true; | |
| } | |
| return { | |
| restrict: 'A', | |
| link: function(scope, el, attr) { | |
| var expState = getExpectedState(scope, attr.ngShowAuth); | |
| assertValidStates(expState); | |
| function fn() { | |
| var show = inList(loginState, expState); | |
| // sometimes if ngCloak exists on same element, they argue, so make sure that | |
| // this one always runs last for reliability | |
| setTimeout(function() { | |
| el.toggleClass('ng-cloak', !show); | |
| }, 0); | |
| } | |
| fn(); | |
| $rootScope.$on('$firebaseSimpleLogin:login', fn); | |
| $rootScope.$on('$firebaseSimpleLogin:logout', fn); | |
| $rootScope.$on('$firebaseSimpleLogin:error', fn); | |
| } | |
| }; | |
| }); |
| <style> | |
| [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { | |
| display: none !important; | |
| } | |
| </style> | |
| <script> | |
| // include the waitForAuth module as a dependency | |
| angular.module('myApp', ['simpleLoginTools']) | |
| // you can use waitForAuth directly from your scripts | |
| .controller('myController', function(waitForAuth) { | |
| waitForAuth.then(function() { | |
| /* do something after auth completes */ | |
| }) | |
| }) | |
| </script> | |
| <!-- ng-cloak now waits for simple login to resolve --> | |
| <div ng-cloak>Authentication has resolved.</div> | |
| <!-- using a string --> | |
| <div ng-show-auth="'login'">{{auth.user.id}} is logged in</div> | |
| <!-- using a $scope variable which equals 'login', 'logout', 'error', or an array of those --> | |
| <div ng-show-auth="variable_name">Logged out</div> | |
| <div ng-show-auth="'error'">An error occurred: {{auth.error}}</div> | |
| <!-- using an array --> | |
| <div ng-show-auth="['logout','error']">This appears for logout or for error condition!</div> |
Seriously. Killer. Thanks!
Upgraded this to work a bit more reliably. Is also now a drag-and-drop plugin suitable for angularFire, angularFire-seed, and generator-angularfire installs.
Sometimes $firebaseSimpleLogin:logout fires before waitForAuth being registered then that promise is never resolved and ng-show-auth is never showed.
@katowulf do u know what could be the problem?
I solve this calling waitForAuth service into app run()
waitForAuth is 'undefined' when I try calling it from my controller, even though I have included 'simpleLoginTools' as a dependency for my app module.
Any ideas?
Hi, I'm having issues with this module and ui-router. I have view setup like this:
app.config(['$stateProvider',
function($stateProvider) {
$stateProvider.state('home', {
url: '/home',
views: {
"main": {
controller: 'HomeController',
templateUrl: 'home/home.tpl.html'
},
"top-nav": {
controller: 'HomeController',
templateUrl: 'home/home-topNav.tpl.html'
}
},
data: {
pageTitle: 'Home'
},
resolve: {
currentUser: ["simpleLogin",
function(simpleLogin) {
// $getCurrentUser returns a promise so the resolve waits for it to complete
return simpleLogin.getCurrentUser();
}
]
}
});
}
]);
My top-nav template looks like this:
<nav class="navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" ui-sref="home">Home</a>
</div>
<div class="control-group nav navbar-nav navbar-right">
<button class="btn btn-default navbar-btn" ng-cloak ng-show-auth="['logout','error']" ui-sref="login">Log In</button>
<button class="btn btn-default navbar-btn" ng-cloak ng-show-auth="login" ng-controller="LoginController" ng-click="logout()">Log Out</button>
<button class="btn btn-default navbar-btn" ng-cloak ng-show-auth="login" ng-click="createStory()">Create Story</button>
</div>
</div>
</nav>
The problem is that ng-show-auth directives are not working. They resolve to 'logout' state even though the user is logged in. When I remove 'resolve' from my route state config, directives work fine. Can you help please?
Updated for AngularFire 0.6 (releasing this coming week)