I am new to Angular js. I have created simple login page. My code is working perfectly. But I want it to route the page , when I login. I went through some of the blog , but I din't got the better approach.
I have created a plunker. Please check it out here.
https://plnkr.co/edit/9O5dHYZMKAqF07y7moVT
Formerly known as Angular then as Angular 1.x is now called AngularJS.
Notice it's one word :)
In order to change a route inside a controller.
( I assume this is what you mean by question since I see some playing with the login information.)
You can use $location.
$location.path(path-to-where-you-wanna-go);
You also need to tell injector to use $location, so your complete controller would look like:
app.controller('credientials', function($scope, $location, authentication) {
$scope.name = 'World';
$scope.cred = 'admin/123';
$scope.templates =
[
{ url: 'login.html' },
{ url: 'practice.html'}
];
$scope.template = $scope.templates[0];
$scope.loginform = function (username, password) {
if ( $scope.username === 'admin' && $scope.password === '123') {
authentication.isAuthenticated = true;
$scope.template = $scope.templates[1];
$scope.user = username;
$scope.info = authentication.isAuthenticated;
$location.path( "/practice" );
} else {
$scope.error = "Invalid username and password";
}
};
});
Assuming you wanna go to /practice route. Note, that you do lack the template and controllers for outer routes. Without it, it won't work.
Related
In my angular application I store the logged in user name in a cookie.
And I want to display this user name in the web page header.
I can retrieve this in my controller as below and display in the page.
$rootScope.fullName = $cookies.get('user');
But instead of doing this in every controller, is it possible to do it in one place and always get this data ?
Update #1:
I don't use ui-view. I use angular route and a sample is as below.
Are there any simple approach please ?
var mdmApp = angular.module('mdmApp');
// Routes
mdmApp.config(function($routeProvider, $httpProvider, $locationProvider) {
$routeProvider
.when('/listScopeAndFrequency/:reportTypeId', {
templateUrl : '3_calendar/listScopeAndFrequencies.html',
controller : "listScopeAndFrequenciesController"
})
.when('/listTemplateFrequencyExceptions/:reportTypeId/:consolidationScopeCode/:frequencyCode', {
templateUrl : '3_calendar/listTemplateFrequencyExceptions.html',
controller : "listTemplateFrequencyExceptionsController"
})
.when('/viewSubmissionDates', {
templateUrl : '3_calendar/viewSubmissionDates.html',
controller : "viewSubmissionDatesController"
})
Update #2
I tried like below but could not get any dynamic values from REST API, I am only able to hard code the value. Not able to read from cookie, localStorage or var all are undefined or give errors.
mdmApp.factory('userService', function($http, $localStorage, $cookies) {
var fullName ;
// Gets user details
$http.get("/mdm/getUser")
.success(function(data, status, headers, config) {
console.log('userService > user : ' +data.fullName);
fullName = data.fullName;
$localStorage.user = data;
$cookies.put('user', data.fullName);
})
.error(function(data, status, headers, config, statusText) {
console.log("Error while retrieving user details.");
});
console.log('fullName : ' +fullName);
console.log('$cookies.get(user) : ' +$cookies.get('user'));
console.log('$localStorage.user : ' +$localStorage.user);
return { name: "hard code only works here"};
});
mdmApp.directive('userTitle', ['userService', function(user) {
console.log('userTitle > user : ' +user);
return {
template: user.name,
};
}]);
Why don't you use a service? Those are specially designed for this task:
Angular services are:
Lazily instantiated – Angular only instantiates a service when an application component depends on it.
Singletons – Each component dependent on a service gets a reference to the single instance generated by the service factory.
How I do it (not necessarily the best way):
setup an independent angular app (non-secured area) for user registration, on login store a token or some identifier in a cookie or the localStorage
when instantiating the full angular app (secured area), create a service which will get back the previous value and inject it whenever you need the user
My User service looks like:
angular.module('app.core')
.service('User', User);
function User($rootScope, localStorageService) {
let user = localStorageService.get('user');
let token = localStorageService.get('userToken');
if(!token) {
//this loads another angular app which has nothing to do with this secured area (on /login)
window.location = '/login'
return;
}
for(let i in user)
this[i] = user[i]
this.token = 'Bearer ' + token;
//note you could reference this to the rootScope so that every scope can have the User object, this can be considered as bad practice!
//$rootScope.user = this;
return this;
}
I would go with a service and a directory for this.
As soyuka explained. Services exists for the purpose of sharing data between parts of an application. I would then use a directive to handle the data in relation to the DOM, that is, to write to the header.
Service/factory:
app.factory('userService', function() {
// do what you have to get your user and save the data.
return { name: 'John'};
});
Directive. Notice the injection of the service. This could be done through a controller if you wish. It depends on whether you want your directives to have a dependency to the service.
app.directive('userTitle', ['userService', function(user) {
// do what you want with the data
return {
template: user.name,
};
}]);
Here the service just returns a dummy name and the directive outputs the name in the DOM.
Here is a running plunker of the setup.
I have spent the entire day on this (hobby-programmer, not a real one). I admit up front that the issue is my lack of understanding of the basic fundamentals of angular (and most programming for that matter). I am especially new to web development and need some help.
Anyways, I have a template that I'm using for learning purposes, that's all this is really. It's the 'ani-theme' from startangular.com. I built some basic logic to authenticate a user (type 'aaa' in the email lol, remember, its just for learning). This code works fine, and if 'aaa' is entered then the router will be triggered to move you to the dashboard.
The problem is that the user could just put the URL for the dashboard in the browser and go there.
I have a variable called "authed" that is set to true once they log in, but I cant seem to 'conditionally route' the user to the dashboard when they type the URL in manually. I have tried so many things but no luck.
After 5 hours of research, i think it is due to the asynchronous nature of angular OR scope issues. Or both. Probably neither. idk.
I saw so many other posts about $stateChangeStart but it went way over my head. Can someone point me in the right direction here or try to explain what is going on here in dummy terms. I mean it, I really don't know much so dumb it down, I wont be insulted.
APP.JS
var authed = false;
var done = false;
var yapp = angular
.module('yapp', [
'ui.router',
'ngAnimate',
'myAuth'
])
.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.when('/dashboard', '/dashboard/overview');
$urlRouterProvider.otherwise('/login');
$stateProvider
.state('base', {
abstract: true,
url: '',
templateUrl: 'views/base.html'
})
.state('login', {
url: '/login',
parent: 'base',
templateUrl: 'views/login.html',
controller: 'LoginCtrl'
})
.state('dashboard', {
url: '/dashboard',
parent: 'base',
templateUrl: 'views/dashboard.html',
controller: 'DashboardCtrl'
})
.state('overview', {
url: '/overview',
parent: 'dashboard',
templateUrl: 'views/dashboard/overview.html'
})
.state('reports', {
url: '/reports',
parent: 'dashboard',
templateUrl: 'views/dashboard/reports.html'
});
});
LOGIN.JS
angular.module('yapp')
.controller('LoginCtrl', function($scope, $location, authFactory) {
$scope.submit = function(emailp) {
if(authFactory.checkAuth(emailp)) {
$location.path('/dashboard');
}else{
alert("WRONG");
}
}
});
AUTH.JS
var myAuth = angular.module('myAuth', [])
.factory('authFactory', function(){
var factory = {};
factory.checkAuth = function(emailp){
if(emailp == 'aaa') authed = true;
return(authed);
};
return factory;
});
IMPORTANT SIDE NOTE
I love advice and help, so please, if you see other things I'm doing that just look ridiculous, please call me out. It will help me a lot.
------------------------------------------------
EDIT EDIT EDIT EDIT EDIT
Thanks for the answers so far! I am going to try implementing #swestner 's answer and once it is working, I will study the 'why' part so I can really understand.
I do have another question on this same issue to clarify so that I can better understand why my other method wasn't working. I am very curious because it is a strange behavior.
So, You see my authed variable is declared in app.js, and then in the auth.js factory it is set to true or false depending on the users 'emailp'.
I added some logic to the app.js saying 'if authed is true, use these route commands, otherwise use these ones.
example:
console.log(authed) //this actually does print the correct value...
if(authed) { //however this doesnt work!
$urlRouterProvider.when('/dashboard', '/dashboard/overview');
$urlRouterProvider.otherwise('/login');
}else{
$urlRouterProvider.when('/dashboard', '/login');
$urlRouterProvider.otherwise('/login');
}
I can print the correct value, however the condition is always true.
HOWEVER, if I declare the variable authed2 RIGHT before the conditional statement it works fine!
var authed2 = true;
console.log(authed + " #1");
console.log(authed2 + ' #2');
if(authed2) {
$urlRouterProvider.when('/dashboard', '/dashboard/overview');
$urlRouterProvider.otherwise('/login');
}else{
$urlRouterProvider.when('/dashboard', '/login');
$urlRouterProvider.otherwise('/login');
}
The program knows both values to be true, I can even print them both right before the conditional, however when I use authed (set and declared elsewhere) the conditional doesnt work (even tho it seems to know the answer).
Its confusing me and I have to be missing some background behavior here.
The $stateChangeStart event is the proper place to handle this. This event will fire when you try to navigate to a url. At that point you can check if the user is authenticated, and if not, bounce them back to login.
You would hook up the event like this :
angular
.module('yapp')
.run(function ($rootScope, $state, authFactory) {
$rootScope.$on('$stateChangeStart', function () {
if(!authFactory.isAuthed()){
$state.go('login')
}
})
});
And update your auth factory to have the isAuthed method.
var myAuth = angular.module('myAuth', [])
.factory('authFactory', function () {
var factory = {};
factory.checkAuth = function (emailp) {
if (emailp == 'aaa') authed = true;
return (authed);
};
factory.isAuthed = function () {
return authed;
}
return factory;
});
Here's my case scenario:
User is not logged in, and they try to access a /settings page.
My Settings controller recognizes based on $auth.isAuthenticated() != true that they aren't logged in, and redirects them to /login
User fills out their email and password and hits submit.
What I would like to do on this third step is then redirect them to the /settings page, not the home page.
I'm thinking I would be changing this variable:
$authProvider.loginRedirect = '/';
The problem is that I cannot include $authProvider in my loginCtrl.js file without getting an "unknown provider" error in my console: https://docs.angularjs.org/error/$injector/unpr?p0= In other words, Angular does not recognize $authProvider when I try to include it. Here's what my loginCtrl.js file looks like:
/* Everything is blowing up because I'm trying to include $authProvider */
angular.module("PrayerChain")
.controller("loginCtrl", ["$rootScope", "$scope", "$state", "$http", "$auth", "$authProvider", loginCtrl]);
function loginCtrl($rootScope, $scope, $state, $http, $auth, $authProvider) {
$authProvider.loginRedirect = '/settings';
$scope.login = function () {
$auth.login({ Email: $scope.email, Password: $scope.password })
.then(function() {
})
.catch(function (response, status, headers) {
console.log(response);
$scope.error = JSON.parse(response.data);
});
};
}
Is including $authProvider in a controller even possible? If not, what's an alternative solution to changing where people are redirected upon logging in using Satellizer?
Thanks.
Usually provider objects can only be accessed at config time, whereas controllers are created in runtime. If you need to setup the authProvider, try doing:
angular.module('PrayerChain').config(
[ "$authProvider",
function($authProvider) {
$authProvider.loginRedirect = '/settings';
}
]).controller("loginCtrl",
// ...
The new version (0.12.5) are not using this settings anymore. You need to set the url inside your controller
$auth.login({ Email: $scope.email, Password: $scope.password })
.then(function() {
$location.path('your-new-route');
})
.catch(function (response, status, headers) {
console.log(response);
$scope.error = JSON.parse(response.data);
});
I was looking to do this and found that in version 0.13.0 (maybe earlier too?) you can pass an options parameter to login function like this:
$auth
.login(user, {
url: config.api + '/authenticate/customer'
})
My basic premise is I want to call back to the server to get the logged in user in case someone comes to the site and is still logged in. On the page I want to call this method. Since I am passing the user service to all my controllers I don't know which controller will be in use since I won't know what page they're landing on.
I have the following User Service
app.factory('userService', function ($window) {
var root = {};
root.get_current_user = function(http){
var config = {
params: {}
};
http.post("/api/user/show", null, config)
.success(function(data, status, headers, config) {
if(data.success == true) {
user = data.user;
show_authenticated();
}
});
};
return root;
});
Here is an empty controller I'm trying to inject the service into
app.controller('myResourcesController', function($scope, $http, userService) {
});
So on the top of my index file I want to have something along the lines of
controller.get_current_user();
This will be called from all the pages though so I'm not sure the syntax here. All examples I found related to calling a specific controller, and usually from within another controller. Perhaps this needs to go into my angularjs somewhere and not simply within a script tag on my index page.
You could run factory initialization in run method of your angular application.
https://docs.angularjs.org/guide/module#module-loading-dependencies
E.g.
app.run(['userService', function(userService) {
userService.get_current_user();
}]);
And userService factory should store authenticated user object internaly.
...
if (data.success == true) {
root.user = data.user;
}
...
Then you will be able to use your factory in any controller
app.controller('myController', ['userService', function(userService) {
//alert(userService.user);
}]);
You need to inject $http through the factory constructor function, for firsts
app.factory('userService', function ($window, $http) {
var root = {};
root.get_current_user = function(){
var config = {
params: {}
};
$http.post("/api/user/show", null, config)
.success(function(data, status, headers, config) {
if(data.success == true) {
user = data.user;
show_authenticated();
}
});
};
return root;
});
in your controller you can say
$scope.get_current_user = UserService.get_current_user();
ng attributes in your html if needed. besides this, i am not sure what you need.
I'm a bit of an Angular newbie. I'm trying to write an Angular service that on any page, will check if a user is logged in, and if not, forward them to a login page, passing their current path as a a GET parameter.
I'm almost there, but it's not quite working. The problem I'm having is as follows: if the user goes to #/articles/my-articles/, they get forwarded to #/login/?next=%2Farticles%2F:module%2F.
In other words, it looks as though Angular is passing the route pattern, not the actual URL.
This is my authentication code:
auth.run(['$rootScope', '$location', '$user', 'TOKEN_AUTH', 'PROJECT_SETTINGS', function ($rootScope, $location, $user, TOKEN_AUTH, PROJECT_SETTINGS) {
var MODULE_SETTINGS = angular.extend({}, TOKEN_AUTH, PROJECT_SETTINGS.TOKEN_AUTH);
$rootScope.$on('$routeChangeStart', function (e, next, current) {
if (next.$$route && !next.$$route.anonymous && !$user.authenticated) {
var nextParam = next.$$route.originalPath;
$location.url(MODULE_SETTINGS.LOGIN + '?next=' + nextParam);
}
});
}]);
I can get the original path in a hacky way using current.params.module - but that doesn't help me, because it seems that routeChangeStart is fired several times and the current object is undefined on all but the last fire.
This is my routes file:
articles.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/articles/:module/', {
templateUrl: 'views/articles/article_list.html',
controller: 'ArticlesListCtrl'
})
.when('/articles/:module/:id/', {
templateUrl: 'views/articles/article_detail.html',
controller: 'ArticlesDetailCtrl'
});
}]);
How can I fix this problem?
auth.run(['$rootScope', '$location', '$user', 'TOKEN_AUTH', 'PROJECT_SETTINGS', function ($rootScope, $location, $user, TOKEN_AUTH, PROJECT_SETTINGS) {
var MODULE_SETTINGS = angular.extend({}, TOKEN_AUTH, PROJECT_SETTINGS.TOKEN_AUTH);
$rootScope.$on('$routeChangeStart', function (e, next, current) {
if (!$user.authenticated) {
$location.url(MODULE_SETTINGS.LOGIN + '?next=' + $location.path());
$location.replace();
}
});
}]);
If logging in is not a AngularJS view, you may have to provide an otherwise route:
(depends on your $locationProvider config)
$routeProvider.otherwise({
template: 'Redirecting…',
controller : 'Redirect'
});
...
articles.controller('Redirect', ['$location', function($location) {
if (someConditionThatChecksIfUrlIsPartOfApp) {
location.href = $location.path();
return;
} else {
// Show 404
}
}]);
Side note: you shouldn't read $$-prefixed properties, they are private AngularJS variables.
Also note: don't use $ prefixes ($user) in your own code, these are public properties, reserved for AngularJS.
My solution works on Angular 1.2.13 :
preventDefault stops angular routing and $window.location sends me out to login page. This is working on a ASP.NET MVC + Angular app.
$rootScope.$on("$locationChangeStart", function (event, next, current) {
event.preventDefault();
$window.location = '/Login';
}
});