My problem is similar to this : ng-show and ng-hide with jwt
Although i modified as instructed by user3735441, i still can't make them work properly:
Service :
'use strict';
/**
* #ngdoc service
* #name ToDoManagerApp.authToken
* #description
* # authToken
* Factory in the ToDoManagerApp.
*/
angular.module('ToDoManagerApp').factory('authToken', function($window) {
var storage = $window.localStorage;
var cachedToken;
var userToken = 'userToken';
var isAuthenticated = false;
// Public API here
var authToken = {
setToken: function(token) {
cachedToken = token;
storage.setItem(userToken, token);
isAuthenticated = true;
},
getToken: function() {
if(!cachedToken)
cachedToken = storage.getItem(userToken);
return cachedToken;
},
isAuthenticated: function() {
return !!authToken.getToken();
},
removeToken: function() {
cachedToken = null;
storage.removeItem(userToken);
isAuthenticated = false;
}
};
return authToken;
});
Controller :
angular.module('ToDoManagerApp').controller('HeaderCtrl', function($scope, authToken) {
$scope.isAuthenticated = authToken.isAuthenticated;
});
HTML :
<div ng-controller = "HeaderCtrl" class="header">
<div class="navbar navbar-default" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#js-navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#/">ToDoManager</a>
</div>
<div class="collapse navbar-collapse" id="js-navbar-collapse">
<ul class="nav navbar-nav">
<li ui-sref-active="active">
<a ui-sref="main">Home</a>
</li>
<li ng-hide="isAuthenticated()" ui-sref-active="active">
<a ui-sref="register">Register</a>
</li>
<li ng-show="isAuthenticated()" ui-sref-active="active">
<a ui-sref="logout">Logout</a>
</li>
</ul>
</div>
</div>
</div>
</div>
What i'm trying to do is to :
1 - show register, hide logout when no token is set (not authenticated) OR
2 - show logout, hide register when a token is set (authenticated)
For now i'm stuck with the first state, authenticated or not i can't see the logout button.
You are accessing the $scope model with ng-hide and ng-show.
In your Service, you are setting isAuthenticated to false, and never setting it to True. So your app is stuck in your first state, where the isAuthenticated is false.
I completly forgot to add 'res' in my register controller, that's why it wasn't updated :
$http.post(url, user)
.success(function(res) {
alert('success', 'OK!', 'You are now registered');
authToken.setToken(res.token);
})
This is happening because your variable in your controller is not updating when it changes in your factory. To work around this, I usually use $broadcast. So in your factory you would have some function like this...
var broadcastValue = function() {
$rootScope.$broadcast('IsAuthenticated');
}
You would then call this function at whatever point you wanted the receivers to check the variable.
Then in your controller you would have something like this to receive the broadcast
$scope.$on('IsAuthenticated', function() {
$scope.isAuthenticated = authToken.isAuthenticated;
});
This will make sure your controller sees when the value changes.
Also see this post.
$on and $broadcast in angular
Related
I am using angularjs and angularjs ui-route. I am building a login page and I want to prevent any user to go to inner pages without logging in. I have found a similar question but it lacks information. Also I want to store session upon successful login.
Here is my homeroute.js
'use strict';
var application = angular.module('App', ['ui.router']);
application.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
// For unmatched routes
$urlRouterProvider.otherwise('/');
// Application routes
$stateProvider
.state('login', {
url: '/login',
templateUrl: './views/login.html',
controller: 'logincontroller'
})
.state('/', {
url: '/',
templateUrl: './views/home.html'
})
.state('customerHome', {
url: '/customerHome',
templateUrl: './views/customerHomepage.html'
})
.state('signup', {
url: '/signup',
templateUrl: './views/register.html',
controller: 'registercontroller'
});
}
]);
application.run(function($rootScope, $location) {
var customerHome = ['/customerHome'];
$rootScope.$on('$routeLogin', function() {
if(customerHome.indexOf($location.path()) != -1 && sessionStorage.getItem('userLogin')) {
$location.path('/login');
}
});
});
application.controller('registercontroller', ['$scope', '$http', function($scope, $http) {
$scope.formData = {};
$scope.userform = "";
$scope.register = function() {
$http({
method: 'POST',
url: './services/loginsubmit.php',
data: $scope.formData
}).then(function(response) {
console.log(response);
if(response.data.empty == true) {
$scope.userform = "Please fill the form.";
} else if(response.data.emailError == true) {
$scope.userform = "Invalid Email.";
} else if(response.data.validation == true) {
$scope.userform = "Username already exists.";
} else if(response.data.validateUsername == true) {
$scope.userform = "Username must be more than 5 characters.";
} else if(response.data.validatePassword == true) {
$scope.userform = "Password must be more than 5 characters.";
} else if(response.data.registerSuccess == false) {
$scope.userform = "Registration Successful.";
$scope.formData = {};
} else if(response.data.registerSuccess == true) {
$scope.userform = "Registration Failed";
}
});
}
}]);
application.controller('logincontroller', ['$scope', '$http', '$location', '$rootScope', function($scope, $http, $location, $rootScope) {
$scope.loginData = {};
$scope.loginUser = "";
$scope.login = function() {
$http({
method: 'POST',
url: './services/loginservice.php',
data: $scope.loginData
}).then(function(response) {
console.log(response);
if(response.data.UsernameLogin == true) {
$scope.loginUser = "Invalid username or password.";
} else {
sessionStorage.setItem('userLogin', response.data.usernameSession);
$location.path('/customerHome');
}
});
}
}]);
Here is my loginservice.php
<?php
include '../connection/connect.php';
$formLogin = json_decode(file_get_contents("php://input"));
$data = array();
$check_UsernameLogin = false;
$username = $formLogin->username;
$password = $formLogin->password;
$login = mysqli_query($conn, "SELECT username FROM customer WHERE username='$username' AND customer_password='$password'");
$check_username = mysqli_num_rows($login);
if($check_username == 0) {
$check_UsernameLogin = true;
} else {
$check_UsernameLogin = false;
}
$data["UsernameLogin"] = $check_UsernameLogin;
$data["usernameSession"] = $login;
echo json_encode($data);
?>
Here is my login.html
<!-- Navigation Bar -->
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#!/">Hostelry Service</a>
</div>
<ul class="nav navbar-nav">
<li>Home</li>
<li>Hostelries</li>
<li>Compare</li>
<li>About Us</li>
<li>Contact</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><span class="glyphicon glyphicon-user"></span> Sign Up</li>
<li><span class="glyphicon glyphicon-log-in"></span> Login</li>
</ul>
</div>
</nav>
<div class="row" style="padding-top: 100px;">
<div class="col-md-4 col-md-offset-4">
<div class="panel panel-primary">
<div class="panel-heading" style="padding-left: 190px;">Log in</div>
<div class="panel-body">
<form method="POST" ng-submit="login()">
<input class="form-control" type="text" ng-model="loginData.username" placeholder="Username"><br>
<input class="form-control" type="password" ng-model="loginData.password" placeholder="Password"><br>
<button type="submit" class="btn btn-primary btn-block">Submit</button><br>
<p class="alert alert-success" ng-show="loginUser">{{loginUser}}</p>
</form>
</div>
</div>
</div>
Here is my customerHomepage.html
<!-- Navigation Bar -->
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#!/">Hostelry Service</a>
</div>
<ul class="nav navbar-nav">
<li>Home</li>
<li>Hostelries</li>
<li>Compare</li>
<li>About Us</li>
<li>Contact</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><span class="glyphicon glyphicon-user"></span> Sign Up</li>
<li><span class="glyphicon glyphicon-log-in"></span> Login</li>
</ul>
</div>
</nav>
<div class="row" style="padding-top: 100px;">
<div class="col-md-4 col-md-offset-4">
<div class="panel panel-primary">
<div class="panel-heading" style="padding-left: 190px;">Log in</div>
<div class="panel-body">
<form method="POST" ng-submit="login()">
<input class="form-control" type="text" ng-model="loginData.username" placeholder="Username"><br>
<input class="form-control" type="password" ng-model="loginData.password" placeholder="Password"><br>
<button type="submit" class="btn btn-primary btn-block">Submit</button><br>
<p class="alert alert-success" ng-show="loginUser">{{loginUser}}</p>
</form>
</div>
</div>
</div>
I am new to using .run() and $rootScope on angularjs.
In the application.run() , you need to check for state change and prevent or allow state change based on whether the user is logged in or not.For ex:
$rootScope.$on('$stateChangeStart', function (event, toState){
if(toState.name === 'login'){
return;
}
else if (!session.getAccessToken()) {
$state.go('login');
event.preventDefault();
}
else{
return;
}
});
Here session is a service.It checks if the access token is found in the session storage.If not found then it prevents user from going to inner pages.
Now,after making a call to login API from your login page,store the access token form the response into your session storage,and change the state to your desired home page.
NOTE: You might prefer using local storage instead of session storage for storing the access token.
To do this with PHP, you need to save user credentials (or login status) to $_SESSION and verify them everytime you serve a file. You need to give your files php extension for compatibility.
Set you index.php to call itself on form submission.
When called with the user name and password, authenticate them, and set the $_SESSION['authenticated'] variable to true in case of authentic login.
Now check this $_SESSION variable everytime you serve your templates.
<?PHP
if ($_SESSION['authenticated'] == false)
die('Permission denied');
?>
However, although it works, there are lot of new and more secure ways to handle this via methods such as jwt.
I started read about modules, components, directives. I would like to ask you to check the code and say how I could improve it. The main thing for me is to figure out how I can improve the transparency of this code. I would also like to learn how to split this code into files, and how it should look like the file structure in this case. I heard that I should make one file for components, But how should it look in the inside?
I would really be grateful for help.
because the most important in the life of the programmer is the code review! :)
(function () {
angular.module('app.navbar', [])
.component('navbar', {
bindings: {
user: '<'
},
controller: function ($scope) {
var navbar = this;
this.$onInit = function () {
navbar.toggle = false;
};
this.activeMenu = function (name, $event) {
this.blockClosingList($event);
if (navbar.toggle === true && $scope.name == name) {
navbar.toggle = !navbar.toggle;
}
else if (navbar.toggle === false) {
navbar.toggle = !navbar.toggle;
}
$scope.name = name;
}
this.blockClosingList = function ($event) {
$event.stopPropagation();
}
},
controllerAs: 'navbar',
template: `
/////// MENU LEFT SIDE ///////
<div class="main-navbar">
<div class="menu-left">
<div class="btns">
<span class="glyphicon glyphicon-align-left btn__glyph"></span>
<span class="btn--name">Tablice</span>
</div>
<div class="btns navbar__search">
<span class="glyphicon glyphicon-search"></span>
</div>
</div>
<div class="navbar__logo">
<span class="navbar--logo">Tasker</span>
</div>
/////// MENU RIGHT SIDE ///////
<div class="menu-right">
<a href="#" ng-click="navbar.activeMenu('Create', $event);">
<div class="btns">
<span class="glyphicon glyphicon-plus"></span>
</div>
</a>
<!-- MENU CREATE -->
<div class="menu menu--create" ng-click="navbar.blockClosingList($event)" ng-class="{active : name === 'Create' && navbar.toggle === true}">
<!--close-->
<menu-create></menu-create>
</div>
<!---->
<!--MENU CREATE BOARD-->
<div class="menu cb__menu-coordinate menu--create-board" ng-click="navbar.blockClosingList($event)" ng-class="{active : name === 'menuCreateBoard' && navbar.toggle === true}">
<span class="settings-menu__header-title">Utwórz Tablicę</span>
<div class="menu__wrapper--create-board center-block">
<menu-create-board></menu-create-board>
</div>
</div>
<!---->
<a href="#" ng-click="navbar.activeMenu('Notice', $event);">
<div class="btns">
<span class="glyphicon glyphicon-bell"></span>
</div>
</a>
<!--NOTIFICATIONS-->
<div class="menu menu--notice" ng-click="navbar.blockClosingList($event)" ng-class="{active : name === 'Notice' && navbar.toggle === true}">
<notifications></notifications>
</div>
<!---->
<a href="#" ng-click="navbar.activeMenu('Profile', $event);">
<div class="btn__circle">
<span class="btn--circle">B</span>
</div>
</a>
<!--MENU PROFILE -->
<div class="menu menu--avatar" ng-click="navbar.blockClosingList($event)" ng-class="{active : name === 'Profile' && navbar.toggle === true}">
<profile-menu></profile-menu>
</div>
</div>
</div>
<!---->
`
})
.component('profileMenu', {
require: {
parent: '^navbar'
},
template: `
<!--close-->
<span class="settings-menu__header-title">
{{$ctrl.parent.user.username}} {{$ctrl.parent.user.role}}
</span>
<ul class="menu__avatar--list">
<li>
Profil
</li>
<li>
<a href="/{{$ctrl.parent.user.username}}">
Karty</a>
</li>
<li>
<a href="/{{$ctrl.parent.user.username}}">
Ustawienia</a>
</li>
<li>
<a href="/logout">
Wyloguj</a>
</li>
</ul>
`
})
.component('notifications', {
require: {
parent: '^navbar'
},
template: `
<!--close-->
<span class="settings-menu__header-title">Powiadomienia</span>
<div class="menu__field--placeholder">
<span>Brak powiadomień</span>
</div>
`
})
.component('menuCreateBoard', {
require: {
parent: '^navbar'
},
template: `
<form>
<div class="form-group">
<label for="">Tytuł</label>
<input type="text" class="form-control">
</div>
<div class="form-group">
<label for="">Zespół</label>
<input type="text" class="form-control">
</div>
<span class="bottom--create-board">Ta tablica będzie Prywatna. Zmień</span>
<button class="btn btn-success">Utwórz</button>
</form>
`
})
.component('menuCreate', {
require: {
parent: '^navbar'
},
template: `
<span class="settings-menu__header-title">Utwórz</span>
<ul class="menu__create--list">
<li>
<a href="#" ng-click="$ctrl.parent.activeMenu('menuCreateBoard', $event);">
<div class="menu__wrapper-create">
<span class="menu-create__heading">Utwórz tablicę</span>
<span class="menu-create__desc">Tablica składa się z kart uporządkowanych w listach. Użyj jej do zarządzania projektami, śledzenia informacji i organizowania wszystkiego.</span>
</div>
</a>
</li>
<li>
<a href="#">
<div class="menu__wrapper-create">
<span class="menu-create__heading">Utwórz zespół</span>
<span class="menu-create__desc">Zespół składa się z ludzi i tablic. Organizuj z jego pomocą firmę, swoją drugą pracę, plany dla rodziny i spotkania z przyjaciółmi.</span>
</div>
</a>
</li>
</ul>
`
})
})();
https://gist.github.com/Turqus/2a791c6b86adfc8b6732711eaec2e23d
in main app:
var App = angular.module('TodoListApp', ['dndLists', 'app.navbar']);
First I would advise you to go here and learn how to use webpack:
https://webpack.github.io/
After you learn how to bundle your files, you should separate templates out of your js files and use templateUrl to load template - you can webpack template loader - works very good.
Then to improve it even further you can learn to use javascript export (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) functionality and separate your code in files.
I like the following directory structure (for example you could use navbar instead of my-component-name):
/my-component-name - directory
my-component-name.component.js - contains my component bindings and templateUrls, also here we import controller for that particular component.
my-component-name.controller.js - sets up controller for component
my-component-name.html - template
my-component-name.scss/less - less/sass file containing isolated styles for that particular component - wrapped in my-component-name {...}
index.js - contains all code put together declaration of angular module, all imports (component,services, directives) and dependencies.
index.js example (you can name it navbar-module.js):
import NavbarComponent from './navbar.component'; // <- here you import component
const NavbarModule = angular
.module('navbar', [])
.component('navbar', NavbarComponent) // <- here you define your component
.name;
export default NavbarModule;
navbar.component.js example:
import templateUrl from './navbar.html';
import controller from './navbar.controller.js'
const NavbarComponent = {
bindings: {
user: '<'
},
templateUrl, // just a shorthand for writing templateUrl: templateUrl
controller, // same as above
}
export default NavbarComponent;
and finally navbar.controller.js:
class NavbarController {
constructor($scope, $timeout) {
this.$scope = $scope;
this.$timeout = $timeout;
}
$onInit() {
// set up your on init code here
this.toggle = true;
}
// set up your functions on controller - they will behave same and you will be able to access them via $ctrl.activeMenu() or $ctrl.blockClosingList() in your templates
activeMenu (name, $event) {
this.blockClosingList($event);
if (this.toggle === true && this.$scope.name == name) {
this.toggle = !this.toggle;
}
else if (this.toggle === false) {
this.toggle = !this.toggle;
}
this.$scope.name = name;
}
blockClosingList($event) {
$event.stopPropagation();
}
}
NavbarController.$inject = ['$scope', '$timeout']; // inject here and put $scope parameter in your constructor
export default NavbarController;
navbar.html - just use your html code it should work fine.
If you need to create some inner functions and keep access to this (controller) you can use arrow functions instead of function (param) {...} just use (param)=>{...} and inside brackets you will have scope of your controller.
One more thing - isolate your components as much as you can and try to communicate to parent components via $emit/$broadcasts instead of requiring parent component like in your example.
Keep in mind what I wrote above is in no way tested and most likely has bugs.
De facto best read about component based architecture in AngularJS can be found here, Todd Motto's styleguide:
https://github.com/toddmotto/angularjs-styleguide
I'm trying to create an SPA website where I have multiple controllers that depend on an AuthService, this service is just in charge of telling all the controllers if the User is signedIn and who the user is. AFAIK since all the controllers share the same service object, the changes should propagate to them, but so far this is not happening.
My code goes as follows:
I have a NavbarController and a LoginController. The NavbarController is in charge of displaying the Login/Logout links depending on the Logged property of the AuthService. The LoginController is in charge of the login panel and calling the login on the server through the AuthService.
AuthService
(function () {
var auth = angular.module('Auth', []);
auth.factory('AuthService', ['$http', function ($http) {
var obj = {};
obj.User = {};
obj.Logged = true;
obj.GetUser = function () {
$http.get('api/Account/UserDetails')
.success(function (data) {
obj.User = data;
obj.Logged = true;
})
}
obj.Login = function (data) {
var func = $http.post('api/Account/Login', data);
func.success(function (data) {
if (data.StatusCode == 200) {
obj.GetUser();
}
});
return func;
}
obj.Logoff = function () {
$http.get('api/Account/Logoff')
.success(function () {
obj.User = {};
obj.Logged = false;
});
}
return obj;
}]);
})();
LoginController
(function () {
var login = angular.module('Login', ['LoginService','Auth']);
login.controller('LoginController', ['accountService','AuthService', function (accountService,authService) {
this.OnFocus = function(obj)
{
$(obj.target).closest(".textbox-wrap").addClass("focused");
}
this.OnBlur = function(obj)
{
$(obj.target).closest(".textbox-wrap").removeClass("focused");
}
this.loginCredentials = {};
this.Login = function () {
authService.Login(this.loginCredentials)
.success(function (data) {
alert(data.StatusCode);
})
.error(function () {
alert("error");
});
}
}]);
login.directive('hcCheckbox', function () {
return {
restrict: 'A',
link: function (scope, element, attr) {
element.iCheck({
checkboxClass: 'icheckbox_square-blue',
increaseArea: '20%' // optional
});
}
}
});
})();
NavbarController
(function () {
var app = angular.module('main');
app.controller('NavbarController', ['AuthService', function (AuthService) {
var self = this;
self.Logged = AuthService.Logged;
self.User = AuthService.User;
self.Logoff = function()
{
AuthService.Logoff();
}
}]);
})();
Navbar html template
<nav class="navbar navbar-default" ng-controller="NavbarController as NavbarCtrl">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="navegacion">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">HACSYS</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="navegacion">
<ul class="nav navbar-nav">
<li class="active">Home</li>
<li>Details</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li ng-hide="NavbarCtrl.Logged">
Login
</li>
<li ng-show="NavbarCtrl.Logged">
<a ng-click="NavbarCtrl.Logoff()" href=""> Logoff</a>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
I know I could use $watch to propagate changes to other controllers, but this way seems cleaner to me, I have seen other examples where this works, and I still can't figure out whats going wrong with my code
In order to ensure that changes are propagated correctly across all the nested scopes, you need to bind to an object by reference. If you bind to a primitive, it creates a copy of the value on scope, effectively breaking the linkage between the scope variables. To resolve this, bind by reference:
app.controller('NavbarController', ['AuthService', '$scope', function (AuthService, $scope) {
var self = this;
$scope.AuthService = AuthService;
self.Logoff = function()
{
$scope.AuthService.Logoff();
}
}]);
When you bind by reference, any controller where you inject AuthService will bind and propagate as expected.
app.controller('otherController', function($scope, AuthService) {
$scope.AuthService = AuthService;
});
HTML
<div ng-controller="otherController">
<div ng-show="AuthService.Logged">
User is logged in!
</div>
</div>
I have the following layout:
<nav ng-include="'views/nav.html'"></nav>
<div class="container-fluid">
<div ng-view></div>
</div>
Inside nav.html I want to display a dropdown link, once someone has entered a page, and has access. This page is rendered in the ng-view div
Right now I am using a service to update the shared value from one controller to the nav controller. However, the value is never updated in the nav controller. It is set in the service, but not updated.
<nav class="navbar navbar-inverse" role="navigation" ng-controller="LoginController as login">
<div class="container-fluid">
<ul class="nav navbar-nav">
<li>Show option '{{login.showOption}}' <span class="glyphicon glyphicon-info-sign"></span></li>
<li ng-if="login.showOption" dropdown>
<a href class="dropdown-toggle" dropdown-toggle>
Options <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a ng-href>1</a></li>
<li><a ng-href>2</a></li>
</ul>
</li>
</ul>
</div>
</nav>
LoginController.js
var LoginController = function (Option) {
var model = this;
model.showOption = Option.getValue();
module.controller("LoginController", ['Option', LoginController]);
}(angular.module("myApp")));
Option.js
'use strict';
(function (module) {
var option = function () {
var value = false;
return {
getValue: function() {
return value;
},
setValue: function(newVal) {
value = newVal;
}
};
};
module.service("Option", option);
}(angular.module("civApp")));
I am updating the Option.getValue() from another controller in another view, however the nav isn't getting updated.
GameController.js
var GameController = function (Option) {
Option.setValue(true);
module.controller("GameController", ['Option', GameController]);
}(angular.module("myApp")));
When I call this code, the view in the nav.html is not updated. I can see that the Option service is called, but I was hoping the value would have been updated in the view also.
GameController
LoginController
Nav.html
I can clearly see in GameController#watch that the Option.value:show is correctly set to true
That can be sorted using by angular dot rule
just update your code to :
Option Service
(function (module) {
var option = function () {
//value.show instead value
var value = {
show: false
};
return {
value: value
};
};
module.service("Option", option);
}(angular.module("civApp")));
and after that in your controllers
Login
var LoginController = function (Option) {
var model = this;
model.showOption = Option.value;
module.controller("LoginController", ['Option', LoginController]);
}(angular.module("myApp")));
GameController
var GameController = function (Option) {
Option.value = {
show: true
};
module.controller("GameController", ['Option', GameController]);
}(angular.module("myApp")));
and finally in your view
<li>Show option '{{login.showOption.show}}' <span class="glyphicon glyphicon-info-sign"></span>
I'm managing authentication with JWT. I'm trying to use ng-hide and ng-show to show/hide login and logout buttons in my nav. It's not working. The token is being stored, but I'm unable to get the show/hide to work.
Service:
angular.module('psJwtApp')
.factory('authToken', function ($window) {
var storage = $window.localStorage;
var cachedToken;
var userToken = 'userToken';
var isAuthenticated = false;
var authToken = {
setToken: function (token) {
cachedToken = token;
storage.setItem(userToken, token);
isAuthenticated = true;
},
getToken: function () {
if(!cachedToken)
cachedToken = storage.getItem(userToken);
return cachedToken;
},
isAuthenticated: function () {
return !!authToken.getToken();
},
removeToken: function () {
cachedToken = null;
storage.removeItem(userToken);
isAuthenticated = false;
}
};
return authToken;
});
Controller:
angular.module('psJwtApp')
.controller('HeaderCtrl', function ($scope, authToken) {
$scope.isAuthenticated = authToken.isAuthenticated();
});
html:
<div ng-controller="HeaderCtrl" class="header">
<ul class="nav nav-pills pull-right">
<li ui-sref-active="active">
<a ui-sref="main">Home</a>
</li>
<li ui-sref-active="active">
<a ui-sref="jobs">Jobs</a>
</li>
<li ng-hide="isAuthenticated()" ui-sref-active="active">
<a ui-sref="login">Log In</a>
</li>
<li ng-show="isAuthenticated()" ui-sref-active="active">
<a ui-sref="logout">Logout</a>
</li>
</ul>
<h3 class="text-muted">psJwt</h3>
</div>
Have you checked the type of $scope.isAuthenticated? i suspect that it has resolved to a boolean, not a function. Update your html to check against the boolean value.
<li ng-show="!isAuthenticated" ui-sref-active="active">
<a ui-sref="login">Log In</a>
</li>
<li ng-show="isAuthenticated" ui-sref-active="active">
<a ui-sref="logout">Logout</a>
</li>