New version Angular 9
Note that the all tests are present inside the sample, but we will see them at the end of this chapter, when all hopefully will be clear.
The entry point will be /api/login
The allowed verbs are
The format of the User will be, in JSON:
{
"userid":"userId",
"password":"userId"
}
Setting the password with the same value of the userid id will let you login.
The service will add
The cookie is offered as a quick facility to check for the login status. But server side, inside the restricted APIs you need ALWAYS to check the session, since the cookie can be easily manipulated!!!
This will act as a wrapper on the login API, as the Contacts service in the previous lessons. The only difference is that it will reset the cookie upon logout.
app.factory('LoginService',['$http',
function($http) {
return {
apiBase : 'api/login/',
http :$http,
isLoggedIn : function() {
return this.http.get(this.apiBase);
},
login: function(user){
return this.http.post(this.apiBase, user);
},
logout: function(){
document.cookie = "";
return this.http.post(this.apiBase+'?request_method=DELETE');
}
}
}
]);
It will have the functions
app.controller('LoginController',['$scope', '$location', 'LoginService',
function($scope,$location, loginService){
$scope.user = {
email: "",
password: ""
};
var getCookie= function(name) {
var cookiename = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++){
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(cookiename) == 0) return c.substring(cookiename.length,c.length);
}
return null;
}
$scope.isLoggedIn = function()
{
return getCookie("userid")!=null;
}
$scope.login = function(user){
loginService.login(user)
.success(function(data) {
if(data.result=="ko"){
$location.path("/login");
}else{
$location.path("/");
}
});
}
$scope.logout = function(){
loginService.logout()
.success(function(data) {
$location.path("/login");
});
}
}
]);
When starting the application we want that an already logged-in user can be redirected directly to the root path "/".
To do this we add a new function to run during the AngularJs startup, that check the cookie status.
This is inside the assets/login/run.js. A separate file, since we don't want to include this inside the application startup when testing!!
app.run(['$http','LoginService',
function($http,loginService){
loginService.isLoggedIn().success(function(data) {
if(data.result=="ko"){
window.location = "#/login";
}else{
window.location = "#/";
}
});
}
]);
We create a new view that will contain the standard things and that will be associated to the LoginController
Note the usage of the utility function "isLoggedIn()" to show hide the login/logout button!
<h2>Login</h2>
<div ng-controller="LoginController">
<form novalidate class="form-horizontal" name="loginForm" id="login-form" method="post" action="" >
<div class="modal-footer" ng-controller="LoginController" ng-show="isLoggedIn()">
<button class="btn btn-primary" id="lgin-btn"
ng-click="logout()">Logout!</button>
</div>
<div ng-show="!isLoggedIn()">
<div class="control-group">
<label class="control-label" for="userid">UserId:</label>
<div class="controls">
<input type="text" name="userid"
ng-model="user.userid" required ng-disabled="isLoggedIn()"/> <show-error for="userid" ></show-error>
</div>
</div>
<div class="control-group">
<label class="control-label" for="password">Password:</label>
<div class="controls">
<input type="password" name="password"
ng-model="user.password" required ng-disabled="isLoggedIn()"//> <show-error use-default for="password"></show-error>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" id="add-new-btn"
ng-disabled="loginForm.$invalid || (isUnchanged(user) && loginForm.$invalid) || isLoggedIn()"
ng-click="login(user)">Login!</button>
</div>
</div>
</form>
</div>
We added a new route to an empty page as root (index.html), and two new roots, contacts and login
function($routeProvider) {
$routeProvider
.when('/', {templateUrl: 'assets/app/index.html',controller: 'EmptyController'})
.when('/contacts', {templateUrl: 'assets/contact/list.html',controller: 'ContactsListController'})
.when('/login', {templateUrl: 'assets/login/login.html',controller: 'LoginController'})
.otherwise({redirectTo: '/'});
}
We should now change our controller.js. Now when an operation is completed we will not redirect to the root but to the "root" of the entity type.
We will then replace, in all functions:
$scope.activePath = $location.path('/');
with
$scope.activePath = $location.path('/'+identifier+'s');
Now we have several routs, thsu we should add a simple menu. We will use the standard bootstrap pills :P
<div class="nav navbar-nav" ng-controller="HeaderController">
<ul class="nav nav-pills">
<li ng-class="{ active: isActive('/')}"><a href="#/">Home</a></li>
<li ng-class="{ active: isActive('/contacts')}"><a href="#/contacts">Contacts</a></li>
<li ng-class="{ active: isActive('/login')}"><a href="#/login">Login/Logout</a></li>
</ul>
</div>
You see we added a new controller. This is needed to check if the current page is active with the isActive function. This will be a globla controller in app.js
It simply check the location path!
app.controller('HeaderController', ['$scope', '$location',
function($scope, $location) {
$scope.isActive = function (viewLocation) {
return viewLocation === $location.path();
};
}
]);

That's it!