AngularJS show dialog from routeProvider - angularjs

Is it possible to [execute a function] e.g. open a modal dialog window from the routeProvider when a certain route is requested?
myApp.config(function($routeProvider) {
$routeProvider
.when('/home',
{
controller: 'HomeCtrl',
templateUrl: 'Home/HomeView.html'
}
).when('/profile/:userId/changepwd',
function(){
$dialog.messageBox(title, msg, btns)
.open()
.then(function(result){
alert('dialog closed with result: ' + result);
});
}
).otherwise({ redirectTo: '/home' });
});
PS: I want to cancel a route and instead open a dialog box. Opening the dialog box is not the only issue. Cancelling the route is the major issue.

You can pass your function as dependency in resolve and it will wait until dependency is resolved and when your dialog ends then change the route and modify history as you wish using $location
var app = angular.module('myApp', [])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {
template: '&nbsp',
controller: //empty function,
resolve: {
data1 : function($dialog, $location) {
var promise = $dialog.messageBox(title, msg, btns)
.open()
.then(function(result){
alert('dialog closed with result: ' + result);
//Use [$location][1] to change the browser history
});
return promise;
}
}
});
}]);

Building on Rishabh's answer, and using sergey's location.skipReload from this Angular Issue you can use the following to create a dialog on route-change, defer the url-change indefinitely (in effect 'cancelling' the route change), and rewrite the URL bar back to '/' without causing another reload:
//Override normal $location with this version that allows location.skipReload().path(...)
// Be aware that url bar can now get out of sync with what's being displayed, so take care when using skipReload to avoid this.
// From https://github.com/angular/angular.js/issues/1699#issuecomment-22511464
app.factory('location', [
'$location',
'$route',
'$rootScope',
function ($location, $route, $rootScope) {
$location.skipReload = function () {
var lastRoute = $route.current;
var un = $rootScope.$on('$locationChangeSuccess', function () {
$route.current = lastRoute;
un();
});
return $location;
};
return $location;
}
]);
app
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/home', {
controller: 'HomeCtrl',
templateUrl: 'Home/HomeView.html'
})
.when('/profile/:userId/changepwd', {
template: ' ',
controller: '',
resolve: {
data1: function($dialog, location, $q){
$dialog.messageBox(title, msg, btns)
.open()
.then(function(result){
//fires on modal close: rewrite url bar back to '/home'
location.skipReload().path('/home');
//Could also rewrite browser history here using location?
});
return $q.defer().promise; //Never resolves, so template '&nbsp' and empty controller never actually get used.
}
}
})
.otherwise({
redirectTo: '/'
});
This feels like it leaks unresolved promises, and there may be a neater solution, but this worked for my purposes.

You can redirect the route to the same partial. You can do this by watching for a change in route using the following code. You can also show a dialog from here.
$rootScope.$on( '$routeChangeStart', function(event, next, current) {
if ( next.templateUrl == "xyz.html" ) {
//other validation logic, if it fails redirect user to the same page
$location.path( "/home" );
}
});

Related

How to restrict the page from redirect after login/ logout in Angularjs?

I need to restrict the user from redirect and need to login only with authentication.
I tried but I can redirect to login page using back button and again come to same page using forward button. Even I can go to the required page using URL without login.
My code :
config.$inject = ['$routeProvider', '$locationProvider'];
function config($routeProvider, $locationProvider ) {
$routeProvider
.when('/login', {
controller: 'LoginController',
templateUrl: 'view/login.view.html',
controllerAs: 'vm'
})
.when('/profileData', {
controller: 'profileDataController',
templateUrl: 'view/profiledata.view.html',
controllerAs :'vm'
})
.when('/questionBank', {
controller: 'questionbankController',
templateUrl: 'view/questionbank.view.html',
controllerAs: 'vm'
})
.when('/dashboard', {
// controller: 'PersonalInfoController',
templateUrl: 'view/dashboard.view.html',
controllerAs:'vm'
})
.otherwise({ redirectTo: '/login' });
}
run.$inject = ['$rootScope', '$location', '$cookieStore', '$http'];
function run($rootScope, $location, $cookieStore, $http) {
// keep user logged in after page refresh
$rootScope.globals = $cookieStore.get('globals') || {};
if ($rootScope.globals.currentUser) {
$http.defaults.headers.common['Authorization'] = 'Basic ' + $rootScope.globals.currentUser.authdata; // jshint ignore:line
}
$rootScope.$on('$locationChangeStart', function (event, next, current) {
//redirect to login page if not logged in and trying to access a restricted page
var restrictedPage = $.inArray($location.path(), ['/dashboard','/questionBank', '/profileData']) === -1;
/* var a = $location.$$absUrl.split('#')[1];
var patt = new RegExp(a);
var res = patt.test(restrictedPage); */
var loggedIn = $rootScope.globals.currentUser;
if (restrictedPage && !loggedIn) {
$location.path('/login');
}
});
}
use this :based on response from server
.when('/login', {
controller: 'LoginController',
templateUrl: 'view/login.view.html',
resolve:{
logincheck: checklogedin
})
/ resolve function for user....
var checklogedin = function($q ,$http,$location)
{
var deferred =$q.defer();
$http.get('/loggedin').success(function(user){
if (user.staus==true)
{
//goo
deferred.resolve();
}
else
{
deferred.reject();
$location.url('/login');
}
});
return deferred.promise
};
Based on the code that you have provided, I can't tell 100% what is going on in your code. But... you could always try to use the resolve property on each route that you don't want to allow access without authentication. Here is what that would look like for questionBank:
.when('/questionBank', {
controller: 'questionbankController',
templateUrl: 'view/questionbank.view.html',
controllerAs: 'vm',
resolve: {
auth: function(AuthService, $q){
if(AuthService.isAuthenticated()) return $q.resolve();
return $q.reject();
}
}
})
Each property of the resolve object should return a promise, and if that resolves... the route change works. If it rejects... the route change is not allowed. If the promise never resolves, you are screwed, so make sure it resolves or it will never do the route.
This isn't the only way to try what you are saying. It is A way of trying it.
You can also add event listener on your $scope and prevent moving in case of unauthenticated user.
$scope.$on('$locationChangeStart', function (event, next, current) {
if (!is_logged_in) {
event.preventDefault();
}
});
In my code I have two main controllers LoginCtrl and AppCtrl, and all other controllers are nested within AppCtrl. Then in AppCtrl I have this code, which will check for logged user.
if (localStorageService.get('authToken') === null) {
$state.go('login', {locale: CONFIG.defaultLang});
} else if (!userService.isLoggedIn()) {
tokenStorage.setAuthToken(localStorageService.get('authToken'));
userService.setIdentity(JSON.parse(localStorageService.get('user')));
}
As you can see I store auth token from server in local storage. When page loades this code will be executed and if you are not logged in you will be redirected. And because all other application controllers are nested within AppCtrl this code will be executed every time.
For more info about nested controllers try for example this article - https://rclayton.silvrback.com/parent-child-controller-communication

In Angular, can view be loaded in code?

Very simply, after an API call, depending on the return value, how is the appropriate view loaded? Consider having
search.html
views/found.html
views/notfound.html
Search's controller makes an AJAX call to a service and gets a good or bad result. Now I want the appropriate view to load, without user having to click. I just can't figure out how to do this and have looked at scores of routing/view examples. I'm using HTML5 mode.
app.config(['$routeProvider', '$locationProvider',
function ($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl: 'search.html',
controller: 'searchCtrl'
})
.when('found', {
templateUrl: 'views/found.html',
controller: 'foundCtrl'
})
.when('notFound', {
templateUrl: 'views/notFound.html',
controller: 'notFoundCtrl'
})
.otherwise({
templateUrl: 'search.html',
controller: 'searchCtrl'
});
$locationProvider.html5Mode({
enabled: true,
requiredBase: true
});
And in the controller ..
$scope.post = function (requestType, requestData) {
var uri = 'Search/' + requestType;
$http.post(uri, requestData)
.success(function (response) {
$scope.searchResult.ID = response.ID;
$scope.searchResult.Value = response.Value;
// how is the view/route loaded without a user click?
'found';
return true;
}).error(function (error) {
// how is the view/route loaded without a user click?
'notFound';
return false;
});
I'm just lost after getting back the response on how to invoke a view within the template.
Since you are using ngRoute use $location.path() instead of $state.go(). The $location.path() method accepts a url specified in route configuration. E.g.:
$location.path('/found');
Say your controller is AppController, then the complete code will look something like:
angular.module('app', ['ngRoute'])
.controller('AppController', function ($location, $http) {
$scope.post = function (requestType, requestData) {
var uri = 'Search/' + requestType;
$http.post(uri, requestData)
.success(function (response) {
$scope.searchResult.ID = response.ID;
$scope.searchResult.Value = response.Value;
// how is the view/route loaded without a user click?
$location.path('/found');
}).error(function (error) {
// how is the view/route loaded without a user click?
$location.path('/notFound');
});
});
Refer https://docs.angularjs.org/api/ng/service/$location for api documentation of $location.path

setup 404 page using $routeProvider in angular js

Working on single page application everything is working fine but getting stuck when want to set 404 page when :username not found or any unexpected url will load in browser please check my code below
controller.js
var myApp = angular.module('assignment', ['ngRoute']);
myApp.service('userData', ['$http', function($http){
return{
userslist : function(){
return $http({'url' : 'js/data.json', 'method' : 'GET'}).then(function(response){
return response.data;
}, function(data){
console.log('some error')
})
}
}
}]);
myApp.config(function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'user-list.html',
controller: 'users'
}).
when('/:username', {
templateUrl: 'detail.html',
controller: 'userdetail'
}).
otherwise({
redirectTo: '/404.html' /*>>>>>>Here is the problem<<<<<<*/
});
});
myApp.controller('userdetail', ['$scope', '$routeParams', 'userData', function($scope, $routeParams, userData){
var selectedUser = $routeParams.username;
selectedUser = selectedUser.replace(/-/g, ' ');
userData.userslist().then(function(data){
$scope.items = [];
angular.forEach(data.data.bst_users, function(item){
if(item.name == selectedUser) {
$scope.user = item;
};
})
})
}])
myApp.controller('userdetail', ['$scope', '$routeParams', 'userData', function($scope, $routeParams, userData){
console.log($routeParams.username);
userData.find($routeParams.username, function(found){
$scope.user = found;
})
console.log(scope.user)
}])
/*******Filters*******/
myApp.filter('removeSpace',function() {
return function(input) {
if (input) {
return input.replace(/\s+/g, '-');
}
}
});
Since you declared /:username as a route, it can match anything after the /, meaning the 404 route isn't really doing anything and the username route in a sense is acting as your catch-all route. This is kind of a weird case, since you can't really define a regular 404 route. But what you could do is have a /404 route, then if /:username doesn't resolve to a user, redirect them to /404. That is the most efficient method I can come up with, but I guarantee there's a better way to do it.
#Jordan points out a definite issue.
I would recommend updating your user detail path to something like the following:
when('/user/:username', {
templateUrl: 'detail.html',
controller: 'userdetail'
})
Just so there is no confusion between /random_username and /unmatched_path.

AngularJS - Determine if the view should be displayed by an ajax call result upon the route changes

To put it simple, I would like to check out that if the session is still alive (which means user has logged in) before displaying the view of some routes, if not, then redirect to log-in view.
I have tried to listen to $routeChangeStart event from inside the log-in page, which is displayed initially by default, but user can still go to other views by typing in the routes.
Now what I am doing is:
(function() {
'use strict';
angular.module("appClubS", ["appClubS.userModule", "appClubS.productModule", "clubsServices", "ngRoute", "ui.bootstrap"])
.config(routeConfigurator);
angular.module("appClubS")
.controller("checkLoginCtrl", checkLoginController);
checkLoginController.$inject = ['$scope', '$rootScope', '$location', 'userFactory'];
routeConfigurator.$inject = ['$routeProvider', '$locationProvider'];
function routeConfigurator($routeProvider, $locationProvider) {
$routeProvider.when("/home", {
templateUrl: "views/index.html"
});
// ...
$routeProvider.when("/account-profile/my-redeem", {
templateUrl: "views/member_zone/my.redeem.html",
controller: 'checkLoginCtrl'
});
$routeProvider.when("/account-profile/my-survey", {
templateUrl: "views/member_zone/my.survey.html",
controller: 'checkLoginCtrl'
});
}
function checkLoginController($scope, $rootScope, $location, userFactory) {
var loginStatus = userFactory.loggedin();
if (!loginStatus) {
alert('Please Login First!');
$location.path('/login');
}
}
})();
But the view still gets displayed before user is navigated to log-in page.
Could anyone help? Thanks so much in advance.
You can use a resolve function
$routeProvider.when("/home", {
templateUrl: "views/index.html",
resolve:{
checkLogin: function (sessionService) {
sessionService.redirectIfLogged();
}
}
});
So this ensures your check is runned before the view is rendered

AngularJS - How to disable access from URL

I'm working with routes :
App.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/home', {
templateUrl: 'orders/list',
controller: OrderController
});
$routeProvider.when('/editOrder', {
templateUrl: 'addOrder/editOrder',
controller: ActionController
});
$routeProvider.otherwise({redirectTo: '/home'});
I want to navigate to the edit page only when a button is clicked, but this definition allows access via url from browser also. Is it possible to disable access via url ?
You can use $routeChangeStart event to implement custom logic on route to be changed and veto navigation depending on some condition/permission. In the following example you can navigate to /edit route only if you have granted permissions, which you can grant or revoke using PermissionsService service. In the following example you can try to navigate via direct link and see that you are redirected to default route, and when you click Edit button you are redirected to the relevant route. Also, if you are on /edit route and make browser back and forward, you can notice that you can't go back to /edit route.
HTML
Home
Edit
<div ng-view></div>
<button ng-click="edit()">Edit</button>
JavaScript
angular.module('app', ['ngRoute']).
config(['$routeProvider', function($routeProvider){
$routeProvider.when('/home', {
templateUrl: 'list.html',
controller: 'OrderController'
});
$routeProvider.when('/edit', {
templateUrl: 'edit.html',
controller: 'ActionController'
});
$routeProvider.otherwise({redirectTo: '/home'});
}]).
run(['$rootScope', '$location', 'PermissionsService', function($rootScope, $location, PermissionsService) {
$rootScope.edit = function() {
PermissionsService.setPermission('edit', true);
$location.path('/edit');
};
$rootScope.$on("$routeChangeStart", function(event, next, current) {
if (next.templateUrl === "edit.html") {
if(!PermissionsService.getPermission('edit')) {
$location.path('/');
}
PermissionsService.setPermission('edit', false);
}
});
}]).
service('PermissionsService', [function() {
var permissions = {
edit: false
};
this.setPermission = function(permission, value) {
permissions[permission] = value;
}
this.getPermission = function(permission) {
return permissions[permission] || false;
}
}]).
controller('OrderController', [function() {}]).
controller('ActionController', [function() {}]);
Live example here.
You can use the resolve property and set some variable on an external service:
App.factory('editMode', function(){
var editMode = false;
return {
getEditMode: function(){ return editMode; },
setEditMode: function(edit) { editMode = edit; }
}
}
And then on the route:
$routeProvider.when('/editOrder', {
templateUrl: 'addOrder/editOrder',
controller: ActionController,
resolve: function(editMode){
if(!editMode.getEditMode()) {
$location.path( "/" );
}
}
});

Resources