Outline
AuthCtrl
and inject Auth
and $state
into it.
angular.module('angularfireSlackApp')
.controller('AuthCtrl', function(Auth, $state){
var authCtrl = this;
});
The $state
service is provided by ui-router
for us to control the state
of our application. We can use the go()
function on $state
to redirect
our application to a specific state. We also create a reference to the this
keyword within our controller because we're using the controller as
syntax.
For more information about this syntax, see this lesson.
angular.module('angularfireSlackApp')
.controller('AuthCtrl', function(Auth, $state){
var authCtrl = this;
authCtrl.user = {
email: '',
password: ''
};
});
This user object will be used with the ng-model
directive in our form. Next,
we'll need two functions on our controller, one for registering users and one
for logging in users. $firebaseAuth
provides us with two functions:
$authWithPassword
for logging in users and $createUser
for registering
users. Both of these functions take a user object like the one we initialized
on our controller, and return a promise. If you're not familiar with how
promises work, read this
to learn more about promises.
login
function in AuthCtrl
:
authCtrl.login = function (){
Auth.$signInWithEmailAndPassword(authCtrl.user.email, authCtrl.user.password).then(function (auth){
$state.go('home');
}, function (error){
authCtrl.error = error;
});
};
When authentication is successful, we want to send the user to the home state. When it fails, we want to set the error on our controller so we can display the error message to our user.
register
function in AuthCtrl
authCtrl.register = function (){
Auth.$createUserWithEmailAndPassword(authCtrl.user.email, authCtrl.user.password).then(function (user){
$state.go('home');
}, function (error){
authCtrl.error = error;
});
};
Our register
function is nearly identical to our login
function, it calls $createUserWithEmailAndPassword
instead of
$signInWithEmailAndPassword
. Now that we have our authentication service and controller created,
let's update our templates and put them to use.
app/index.html
, include the auth service and controller after where
app.js
is included.
<script src="app.js"></script>
<script src="auth/auth.controller.js"></script>
<script src="auth/auth.service.js"></script>
app/app.js
, specify AuthCtrl
as our controller for both the login
and
register
states.
.state('login', {
url: '/login',
controller: 'AuthCtrl as authCtrl',
templateUrl: 'auth/login.html'
})
.state('register', {
url: '/register',
controller: 'AuthCtrl as authCtrl',
templateUrl: 'auth/register.html'
})
app/auth/register.html
, add ng-submit
to the form and specify
authCtrl.register()
as the submit function.
ng-model="authCtrl.user.email"
to the email input.
ng-model="authCtrl.user.password"
to the password input.
The resulting form should look like this:
<form ng-submit="authCtrl.register()">
<div class="input-group">
<input type="email" class="form-control" placeholder="Email" ng-model="authCtrl.user.email">
</div>
<div class="input-group">
<input type="password" class="form-control" placeholder="Password" ng-model="authCtrl.user.password">
</div>
<input type="submit" class="btn btn-default" value="Register">
</form>
div
just above the form:
<div ng-show="authCtrl.error">
<span>{{ authCtrl.error.message }}</span>
</div>
This div will remain hidden until our authentication controller reaches an error, in which case the error message it will get displayed to our user. Next, let's update our login template in a similar fashion.
app/auth/login.html
, add ng-submit="authCtrl.login()"
to the form.
ng-model="authCtrl.user.email"
to the email input.
ng-model="authCtrl.user.password"
to the password input.
<form ng-submit="authCtrl.login()">
<div class="input-group">
<input type="email" class="form-control" placeholder="Email" ng-model="authCtrl.user.email">
</div>
<div class="input-group">
<input type="password" class="form-control" placeholder="Password" ng-model="authCtrl.user.password">
</div>
<input type="submit" class="btn btn-default" value="Log In">
</form>
div
that we did for the register view just above the
form for error handling:
<div ng-show="authCtrl.error">
<span>{{ authCtrl.error.message }}</span>
</div>
Now we should have a working register and login system, but we have no way of
telling if the user is logged in or not. The login and registration pages are
still accessible if we are authenticated. We can resolve this by using the
resolve
property on our states. resolve
allows us to create dependencies
that can be injected into controllers or child states. These dependencies can
depend on services in our app that return promises, and the promises will get
resolved before our controller gets instantiated. Read the ui-router Github Wiki
if you're not familiar with how resolve
works with ui-router
.
login
and register
state:
resolve: {
requireNoAuth: function($state, Auth){
return Auth.$requireSignIn().then(function(auth){
$state.go('home');
}, function(error){
return;
});
}
}
The $firebaseAuth
service provides us with a $requireSignIn
function which
returns a promise. This promise will get resolved with an auth
object if the
user is logged in. The Firebase Documentation
provides a table of what information is available to us within auth
. If the
user is not authenticated, the promise gets rejected. In our requireNoAuth
dependency, if the User is logged in we want to send them back to the home
state, otherwise, we need to catch the error that gets thrown and handle it
gracefully by returning nothing, allowing the promise to be resolved instead
of rejected. Now, we should no longer be able to access the login or register
states if we're authenticated.
Check your work
You can view the completed & working code for this tutorial here: