I am trying to build a dynamic sidebar, which displays elements depending on the current user state. So only some elements should be displayed, if the user is logged in and some others, if the the user isn´t.
The current state is saved in the userService. There also is a method, which return the current state:
angular.module('app').service('userService', ['$http', 'base64', function ($http, base64) {
var user = {
auth: "",
ask: "",
mandant: ""
};
...
this.isloggedIn = function(){
if(user.auth != "" && user.ask != "" && user.mandant != "")
{
return true;
}
else
{
return false;
}
...
}]);
Now I created a small controller:
angular.module('app')
.controller('sidebarController',['$scope', 'userService', function($scope, userService) {
$scope.loggedIn = userService.isloggedIn();
}]);
My sidebar looks like this:
<div class="scrollable" ng-controller="sidebarController">
<h1 class="scrollable-header app-name">Navigation</h1>
<div class="scrollable-content">
<div class="list-group" ui-turn-off='uiSidebarLeft'>
<a class="list-group-item green" href="#/login" ng-hide="loggedIn">Login</a>
<a class="list-group-item red" href="#/logout" ng-show="loggedIn">Logout</a>
</div>
</div>
</div>
The Goal : The sidebar should only display the login element, if the user is logged out and only the logout element, if the user is logged in.
After runing this, the sidebar only displays the login element, but after login the sidebar do not change. How can i force the sidebar to refresh?
Your problem is that
$scope.loggedIn = userService.isloggedIn();
is only being called once: on initiating the controller. What you want is to create a function which is being called whenever the state changes (e.g. after login):
angular.module('app').controller('sidebarController', ['$scope', 'userService', function($scope, userService) {
function refreshState() {
$scope.loggedIn = userService.isloggedIn();
}
refreshState();
$scope.login = function() {
// do login
// call refreshState() afterwards
refreshState();
}
}]);
Related
I gather several possible solutions none of them work for me. Can someone tell which part has error.
This is the logout function I am working on, the icon should disappear if user click logout and back to login page, but now it only lead to login page. Icon is still there because the function didn't trigger.
Everything works only AFTER I click the button in login page,
navigation.service.js
(function() {
angular
.module('TheApp')
.service('authentication', ['$window', function($window) {
var saveToken = function(token) {
$window.localStorage['auth-token'] = token;
}
var getToken = function() {
return $window.localStorage['auth-token'];
}
var logout = function() {
$window.localStorage.removeItem('auth-token');
//delete $window.localStorage['auth-token'];
//$window.localStorage.clear();
}
var isLoggedIn = function() {
var token = getToken();
//Get token from storage If token exists get payload, decode it, and parse it to JSON
if (token) {
let payload = JSON.parse($window.atob(token.split('.')[1]));
return payload.exp > Date.now() / 1000;
} else {
return false;
}
}
return {
saveToken: saveToken,
getToken: getToken,
isLoggedIn: isLoggedIn,
logout: logout
};
}])})();
navigation.directive.js
(function() {
angular
.module('TheApp')
.directive('navigation', navigation);
function navigation() {
return {
restrict: 'EA',
templateUrl: './common/directives/navigation/navigation.template.html',
controller: 'navigationCtrl as navvm'
};
}})();
navigation.controller.js
(function() {
angular
.module('TheApp')
.controller('navigationCtrl', ['$location', 'authentication', '$window', function($location, authentication, $window) {
console.log("enters navigation controller");
var vm = this;
vm.isLoggedIn = authentication.isLoggedIn();
vm.logout = function() {
console.log('test if the link work');
authentication.logout();
$location.path('/login');
};
}]);})();
navigation.template.html
<ul class="nav navbar-nav navbar-right">
<li ng-show="navvm.isLoggedIn">
<a href="" ng-click="navvm.logout()">
<span aria-hidden="true" class="glyphicon glyphicon-log-out"></span></a></li>
</ul>
Thanks.
Solution(UPDATE):
A careless situation, I omit to put the controller link inside index.html (main template page). So if anyone working on the similar project, the code above should works without errors.
Explanation :
I created a header directive for my angular application. By using this directive we are loading template by using templateUrl property of attribute based on some conditions.
html :
<div header></div>
directive :
app.directive('header', ['LS', function(LS) {
'use strict';
var user = LS.getData() === 'true' ? true : false;
return {
restrict: 'A',
replace: true,
templateUrl: user ? 'withlogin-header.html' : 'withoutlogin-header.html',
controller: ['$scope', 'LS', function ($scope,LS) {
$scope.login = function() {
return LS.setData(true);
}
$scope.logout = function() {
return LS.setData(false);
}
}]
}
}]);
withlogin-header.html :
<div>
User is logged in !!!
<input type="button" ng-click="logout()" value="Logout"/>
</div>
withoutlogin-header.html :
<div>
Hey buddy, log in !!!
<input type="button" ng-click="login()" value="Login"/>
</div>
Requirement :
We have to display different headers based on the user roles.i.e if user was not login then we have to display normal header with login button and if user already login then we have to display different header with logout button.
Challenge we are facing :
header directive is not working properly. when we click on the login button from withoutlogin-header.html it not loading another template withlogin-header.html based on the defined condition in the templateUrl property of the directive.
I tried so far :
Plnkr : http://plnkr.co/edit/w7AyUjSNA1o5NJp6tD1p?p=preview
Any immediate help will be highly appreciable. Thanks
Checkout this plunker i have created an amazing directive for fetching dynamic header template from server.
I have made some little changes to your code as well.
Hope it will help you surely...
http://plnkr.co/edit/GWIozm?p=preview
You could put the templates into a single directive:
html:
<div ng-if="!isLoggedIn">
Hey buddy, log in !!!
<input type="button" ng-click="login()" value="Login"/>
</div>
<div ng-if="isLoggedIn">
Hey buddy, log in !!!
<input type="button" ng-click="login()" value="Login"/>
</div>
directive:
app.directive('header', function() {
'use strict';
return {
restrict: 'A',
replace: true,
templateUrl: 'withlogin-header.html',
controller: ['$scope', 'LS', function ($scope,LS) {
$scope.isLoggedIn = false;
$scope.login = function() {
LS.setData(true);
$scope.isLoggedIn = LS.getData() === 'true';
}
$scope.logout = function() {
LS.setData(false);
$scope.isLoggedIn = LS.getData() === 'true';
}
}]
}
});
EDIT: or if you want to stick to separate template files, you could use ng-include as #Stepan Kasyanenko mentioned.
I have a similar situation in that I display a certain list of URLS for anonymous users and a different list once the user is logged in. I approached this solution by adding a $watch on the user's logged in property as well as the user's selected language at login (coding for multiple countries)
$scope.$watch(function () {
return User.language;
}, function (newVal, oldVal) {
if (newVal === undefined) {
newVal = "english";
}
navBarCtrl.AnonymousUrls = [];
navBarCtrl.AuthenticatedUrls = [];
$http.get('http://localhost:#####/Urls/' + newVal)
.success(function (data) {
navBarCtrl.sortAllUrlLists(data, navBarCtrl.AnonymousUrls, navBarCtrl.AuthenticatedUrls);
});//end of http get
}, true);
$scope.$watch(function () {
return User.isAuthenticated;
}, function (newVal, oldVal) {
navBarCtrl.isUserAuthenticated = newVal;
}, true);
These two properties are set when the user logs in using the following
this.submit = function () {
var data = angular.toJson(submitForm.credentials);
$http.post("/submitLogin", data)
.success(function (data, status, headers, config) {
submitForm.user.isAuthenticated = true;
submitForm.user.username = data.username;
submitForm.user.location = data.location;
submitForm.user.dsn = data.dsn;
submitForm.user.language = data.language;
$location.path(User.intededPath);
})
.error(function (data, status, headers, config) {
submitForm.user.isAuthenticated = false;
alert("fail");
}); // end of $http.post
} // end of submit
Finally in the view I have the following to display the correct list based on whether or not the user is logged in
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li ng-class="{'dropdown':urlList.length>1}" ng-show="!navBarCtrl.isUserAuthenticated" ng-repeat="urlList in navBarCtrl.AnonymousUrls">
{{urlList[0].Label}}
<ul class="dropdown-menu" ng-if="urlList.length>1">
<li ng-repeat="url in urlList" ng-if="$index > 0">
{{url.Label}}
</li>
</ul>
{{urlList[0].Label}}
</li>
<li ng-class="{'dropdown':urlList.length>1}" ng-show="navBarCtrl.isUserAuthenticated" ng-repeat="urlList in navBarCtrl.AuthenticatedUrls">
{{urlList[0].Label}} <b class="caret"></b>
<ul class="dropdown-menu" ng-if="urlList.length>1">
<li ng-repeat="url in urlList" ng-if="$index > 0">
{{url.Label}}
</li>
</ul>
{{urlList[0].Label}}
</li>
</ul>
</div>
Hopefully that might give you an idea on how to get yours working.
I have a login controller
myApp.controller('LoginCtrl', ['$scope', '$http','$location', function($scope, $http, $location) {
$scope.login = function() {
var data = JSON.stringify({user: $scope.user.id, password: $scope.user.password, type: "m.login.password"});
$http.post("http://localhost:8008/_matrix/client/api/v1/login", data).then(function mySuccess(details){
$http.post('/login',details.data).success(function(response){
console.log(response);
});
$location.path('home');
}, function myError(err) {
console.log(err);
alert("Invalid username/password")
});
};
}]);
and a home controller
myApp.controller('HomeCtrl', ['$scope', '$http','$location', function($scope, $http, $location) {
console.log("Hello World from home controller");
var refresh = function() {
$http.get('/roomNames').success(function(response) {
console.log("I got the data I requested");
$scope.roomNames = response;
});
}
refresh();
}]);
As seen, if the login details are correct, the LoginCtrl changes the route to be home.html.
However, when I run the application and login successfully, the HomeCtrl is supposed to make a get request to the server for data for the logged in user.
What I want is this data to be loaded as a list in the home.html. Here's my home.html
<h3 class="subHeader"> Rooms </h3>
<ul class="nav nav-sidebar">
<!-- <li class="active">Overview <span class="sr-only">(current)</span></li> -->
<li ng-repeat="room in roomNames"><a>{{room}}</a></li>
</ul>
However, on successful login, the roomNames variable is empty initially. As soon as I refresh the page, the html list gets populated.
How do I ensure the list is populated as soon as the home.html page opens?
try using the success and errorcallbacks from $http, it would be better to place this functionality into a factory
myApp.controller('HomeCtrl', ['$scope', '$http', '$location',
function($scope, $http, $location) {
console.log("Hello World from home controller");
var refresh = function() {
$http.get('/roomNames')
.then(function successCallback(response) {
$scope.roomNames = response;
}, function errorCallback(response) {
//output an error if failed?
});
}
refresh();
}
]);
This is because, you move on to home page before your server you access. Therefore, on the home page, you will not get the data, and get them after the refresh.
Do redirected to the page only after successful authentication.
myApp.controller('LoginCtrl', ['$scope', '$http','$location', function($scope, $http, $location) {
$scope.login = function() {
var data = JSON.stringify({user: $scope.user.id, password: $scope.user.password, type: "m.login.password"});
$http.post("http://localhost:8008/_matrix/client/api/v1/login", data).then(function mySuccess(details){
$http.post('/login',details.data).success(function(response){
console.log(response);
$location.path('home'); // Redirect after success login
})
.catch(function(data){
console.error("Error in login",data);
});
}, function myError(err) {
console.log(err);
alert("Invalid username/password")
});
};
}]);
I have login and logout buttons that change dynamically after login.
<ul class="nav navbar-nav navbar-right" ng-controller="loginController">
<li class="dropdown">
<a href data-ng-show="token" ng-click="logout()"><b>Logout</b></a>
<a href data-ng-hide="token" data-toggle="dropdown"><b>Login</b></a>
</li>
</ul>
So after I login, the button changes to logout using ng-hide but the same button doesn't change back to login after I log out?
Do I have to do a scope watch on the variables? I have the code like this using ui-router and states:
myApp.config(function ($stateProvider, $urlRouterProvider, $httpProvider) {
// For any unmatched url, redirect to /login
$urlRouterProvider.otherwise("/Login");
var header = {
templateUrl: 'views/Header.html',
controller: function ($scope) {
}
};
var footer = {
templateUrl: 'views/Footer.html',
controller: function ($scope) {
}
};
// Now set up the states
$stateProvider
.state('Login', {
url: "/Login",
views: {
header: header,
content: {
templateUrl: 'views/Login.html',
controller: function ($scope) {
}
},
footer: footer
}
})
.state('LoggedIn', {
url: "/LoggedIn",
views: {
'header': header,
'content': {
templateUrl: 'views/LoggedIn.html',
controller: function ($scope) {
}
},
'footer': footer
},
data: {
requiresLogin: true
}
});
Login controller where I am storing token in localstorage(as store in my case) to update the login/logout buttons using ng-show
myApp.controller('loginController', ['$rootScope', '$scope', 'Auth', '$state', 'jwtHelper', 'store',
function ($rootScope, $scope, Auth, $state, jwtHelper, store) {
function successAuth(res) {
var decodedToken = jwtHelper.decodeToken(res.token);
store.set('jwt', res.token);
store.set('email', decodedToken.email);
if (store.get('jwt')) {
$state.go("LoggedIn");
} else {
alert("Invalid username or password");
}
}
$scope.signup = function () {
var formData = {
email: $scope.email,
password: $scope.password
};
Auth.signup(formData, successAuth, function () {
$rootScope.error = 'Failed to signup';
});
};
$scope.logout = function ()
{
Auth.logout(function () {
$state.go("Login");
console.log("token after logout is :" + store.get('jwt'));
});
};
$scope.token = store.get('jwt');
}]);
Update:
Lets say after logging-in, Its routing from "Home" to "AboutUs" page with button shown as "Logout" and then if I logout it routes back to "Home" where the button is shown as "Login"
but the problem is after logging-in if I manually route to "Home" and then I click on "Logout" button, the button stays as "Logout" even when token is set to null;
You can try by making following changes in html:
<ul class="nav navbar-nav navbar-right" ng-controller="loginController">
<li class="dropdown">
<a href ng-if="isLogin" ng-click="logout()"><b>Logout</b></a>
<a href ng-if="!isLogin" data-toggle="dropdown"><b>Login</b></a>
</li>
</ul>
And modification in javascript will be :
function successAuth(res) {
var decodedToken = jwtHelper.decodeToken(res.token);
store.set('jwt', res.token);
store.set('email', decodedToken.email);
if (store.get('jwt')) {
$state.go("LoggedIn");
$scope.isLogin = true; // Added a new scope
} else {
alert("Invalid username or password");
}
}
$scope.logout = function ()
{
Auth.logout(function () {
$state.go("Login");
$scope.isLogin = false; // Added a new scope
console.log("token after logout is :" + store.get('jwt'));
});
};
$scope.isLogin = !angular.isUndefined(store.get('jwt')); // Add this line also.
I hope it works for you.!!
Use ng-show in both the places or ng-hide in both places and on success of logout make the flag token opposite of what it currently is.That must work
OK so I've tried Googling for it and have read several of the various questions posted on here, but none seem to address the issue I have currently.
I'm working with angular and using the angular-bootstrap ui. When the user clicks on the login button on the homepage a modal pops up giving them options. I can sign in through Facebook, Twitter, etc just fine. But when the new user welcome page the scope for the modal instance is still there. This isn't a huge issue but annoying and I'd rather not have unnecessary scope creep slowing down my client side.
Here a walk through of my issue using pictures. So the user hits the homepage as seen below.(ok I couldn't post images because my reputation isn't a 10 so here's a link to them.)
https://scontent-b.xx.fbcdn.net/hphotos-prn2/t1.0-9/1538681_313638755452846_5694320198249084494_n.jpg
As the photo shows the scope is limited to that of the controller for the view. Then the user clicks on the Login button and the modal pops up. (As can be seen in the following link)
so it wouldn't let me post more than 2 links because my reputation isn't a 10 so I had to disguise this one.
https (remove me)://fbcdn-sphotos-b-a.akamaihd.net/hphotos-ak-frc1/t1.0-9/1926680_313638758786179_2230027955019442405_n.jpg
If you look at the scope you'll see that I've circled in red the newly added scope for the modal. When the user selects a provider to log-in with he/she is taken to the new user page as can be seen in the following link.
https://scontent-b.xx.fbcdn.net/hphotos-prn2/t1.0-9/10155397_313638762119512_900295349985269066_n.jpg
A portion of the modal scope is still present, even though it's not in use anymore. I don't know how to remove it. True if I reload the page the scope will disappear but I don't want to force a reload simple to remove scope. Especially when it's not currently noticeable or slowing it down. Is there a way to remove this scope without a reload?
Here's my current code.
The Controller:
'use strict';
angular.module('triviumApp')
.controller('HomepageCtrl', function ($log, $modal, $scope, UserFactory, $location) {
$scope.user = UserFactory;
$scope.awesomeThings = [
'HTML5 Boilerplate',
'AngularJS',
'Karma'
];
$scope.items = ['item1', 'item2', 'item3'];
$scope.close = function (){
$modal.close();
};
$scope.login = function (type){
console.log("hi");
$scope.user.login(type);
};
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'LoginModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
user: function () {
return $scope.user;
}
}
});
modalInstance.result.then(function (provider) {
//They logged in
$scope.user.login(provider);
}, function (event) {
//the Modal was dismissed so the user didn't log in.
$log.info('Modal dismissed at: ' + new Date() + event);
});
};
}
);
// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.
var ModalInstanceCtrl = function ($scope, $modalInstance) {
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
$scope.login = function (provider){
$modalInstance.close(provider);
};
};
Here's the View:
<div class="header">
<ul class="nav nav-pills pull-right">
<li class="active"><a ng-href="#">Home</a></li>
<li><a ng-href="#">About</a></li>
<li><a ng-href="#">Contact</a></li>
<li ng-show="user.getLoginStatus">Login</li>
<!--<li ng-show="user.getLoginStatus">Logout</li>-->
</ul>
<h3 class="text-muted">Temp Title</h3>
</div>
<script type="text/ng-template" id="LoginModalContent.html">
<div class="modal-body">
<button type="button" class="close pull-right" aria-hidden="true" ng-click="cancel()">×</button>
<fieldset>
<legend class="bold">Login/Sign-up</legend>
<div class="login-icons center-block">
<span class="facebook icon"></span>
<span><span class="github icon"></span></span>
<!--<span><span class="google icon"></span></span>-->
<span><span class="persona icon"></span></span>
<span><span class="twitter icon"></span></span>
</div>
</fieldset>
</div>
</script>
Here's the User Factory -- (Note I removed my firebase key so it won't have access to my firebase account so if you test it you'll need to add your key and setup your Firebase account to work with Facebook, or twitter.
'use strict';
var User = angular.module('UserApp', ['firebase']);
User.factory('UserFactory', ['$firebase', '$window', function ($firebase, $window){
//Firebase Variables
var user = {
'name': null,
'id': null,
'address': null,
'email': null,
'gender': null,
'loggedIn': false
};
var firebase = new Firebase("YOUR FIREBASE KEY HERE");
var auth = new FirebaseSimpleLogin(firebase, function(error, response) {
if (error) {
// an error occurred while attempting login
} else if (user) {
// user authenticated with Firebase
console.log('Auth', response);
if(response !== null) {
getUser(response);
}
} else {
// user is logged out
}
});
function getUser(firebaseInfo){
if(firebaseInfo !== null && firebaseInfo.firebaseAuthToken !== null){
user.id = firebaseInfo.firebaseAuthToken.split('.')[0];
firebase.child(user.id).once('value', function(snap){
if(snap.val() === null){
populateUser(firebaseInfo, snap, true);
}
else{
//Check to see if user used a different provider
populateUser(firebaseInfo, snap, false);
}
});
}
}
function populateUser (firebaseInfo, snap, newUser){
var provider = firebaseInfo.provider;
//Create the user in the firebase table
firebase.child(user.id);
if(provider === 'facebook'){
if(newUser){
console.log('Here');
facebookUser(firebaseInfo);
$window.location.href ='/#/new-user';
} else{
if(!snap.val().Facebook_ID){
facebookUser(firebaseInfo);
}
}
} else if(provider === 'github'){
if(newUser){
githubUser(firebaseInfo);
$window.location.href('/new-user');
} else{
if(!snap.val().GitHub_ID){
githubUser(firebaseInfo);
}
}
} else if(provider === 'persona'){
if(newUser){
personaUser(firebaseInfo);
$window.location.href('/new-user');
} else{
if(!snap.val().Persona_ID){
personaUser(firebaseInfo);
}
}
}else if(provider === 'twitter'){
if(newUser){
twitterUser(firebaseInfo);
$window.location.href('/new-user');
} else{
if(!snap.val().Twitter_ID){
twitterUser(firebaseInfo);
}
}
}
}
function facebookUser (firebaseInfo){
firebase.child(user.id).update({'Facebook_ID': firebaseInfo.id});
firebase.child(user.id).update({'Facebook_Link': firebaseInfo.thirdPartyUserData.link});
user.name = firebaseInfo.name.split(' ');
user.gender = firebaseInfo.thirdPartyUserData.gender;
if(user.name[0] && user.name[1]) {
firebase.child(user.id).update({'Name-First': user.name[0], 'Name-Last': user.name[1]});
}
if(user.gender){
firebase.child(user.id).update({'Gender': firebaseInfo.thirdPartyUserData.gender});
}
}
function githubUser (firebaseInfo){
firebase.child(user.id).update({'GitHub_ID': firebaseInfo.id});
firebase.child(user.id).update({'GitHub_Link': firebaseInfo.thirdPartyUserData.html_url});
firebase.child(user.id).update({'Email': firebaseInfo.thirdPartyUserData.emails[0].email});
}
function personaUser (firebaseInfo){
firebase.child(user.id).update({'Persona_ID': firebaseInfo.id});
}
function twitterUser (firebaseInfo){
firebase.child(user.id).update({'Twitter_ID': firebaseInfo.id});
user.name = firebaseInfo.name.split(' ');
if(user.name[0] && user.name[1]) {
firebase.child(user.id).update({'Name-First': user.name[0], 'Name-Last': user.name[1]});
}
}
return {
login: function (provider){
if(provider !== undefined && provider !== '' && provider !== null){
auth.login(provider);
}
},
logout: function (){
auth.logout();
},
getLoginStatus: user,
getMyAddress: function (){
return user.address;
},
getMyEmail: function (){
return user.email;
},
getMyName: function (){
return user.name;
},
updateMyName: function (first, last){
if(user.id != null){
firebase.child(user.id).update({'First_Name': first});
firebase.child(user.id).update({'Last_Name': last});
}
},
updateMyEmail: function (email){
if(user.id != null){
firebase.child(user.id).update({'Email': email});
}
},
updateMyAddress: function (address){
if(user.id != null){
firebase.child(user.id).update({'Address': address});
}
}
}
}]);
Thanks for the help. :-)