Setting multiple controllers in one state, IONIC - angularjs

I want to check if there is a user signed in, for it to redirect to another page, if there is no user, i want to redirect to the homePage. The home page has a controller called storeCtrl.
I tried this:
.state('homePage',
{
url: '/homePage',
templateUrl: 'templates/homePage/homePage.html',
controller:'storeCtrl',
function ($localStorage,$state) {
if ($localStorage.user) {
$state.go('tabs.profile');
} else {
$state.go('homePage');
}
}
})
but it doesn't work. I tried this also:
.state('homePage',
{
url: '/homePage',
templateUrl: 'templates/homePage/homePage.html',
controller:
function ($localStorage,$state) {
if ($localStorage.user) {
$state.go('tabs.profile');
} else {
$state.go('homePage'),
controller:storeCtrl
}
}
})
but that also didn't work.

instead of putting it in the state. try to add this inside app.run
app.run(function($ionicPlatform,$state,$rootScope,$localStorage) {
$ionicPlatform.ready(function() {
//your code
})
$rootScope.$on('$stateChangeStart', function (event,next, nextParams, fromState,fromParams) {
var nextScreen=next.name;
if (nextScreen!="homePage" && $localStorage.user===undefined) {
event.preventDefault();
$state.go('homePage');
return;
}
});
})

Related

how to dynamically set templateUrl in ionic tabs?

Is it possible to pass a templateUrl parameter to the .state tab definitions similar to the following? I have multiple different pages to write and don't want a bunch of nested ng-ifs within a single template to parse out which "html" page to show:
.state('tab.menu', {
url: '/menu',
views: {
'tab-menu': {
templateUrl: 'templates/tab-menu.html',
controller: 'MenuCtrl'
}
}
})
.state('tab.menu-detail', {
url: '/menus/:menuID',
views: {
'tab-menu': {
templateUrl: function($stateParams,Menus) {
console.log("In function") ;
console.log("Template: " + Menus.get($stateParams.menuID).url) ;
return 'templates/' + Menus.get($stateParams.menuID).url ;
},
controller: 'MenuSubCtrl'
}
}
})
// controllers
.controller('MenuCtrl', function($scope,Menus) {
$scope.menus = Menus.all() ;
})
.controller('MenuSubCtrl', function($scope,$stateParams,Menus) {
$scope.menu = Menus.get($stateParams.menuID);
})
// services
.factory('Menus', function() {
var menus = [
{name:"Account",url:"menu-account.html",menuID:0},
{name:"Contact",url:"menu-contact.html",menuID:1},
{name:"Help",url:"menu-help.html",menuID:2},
{name:"Privacy",url:"menu-privacy.html",menuID:3},
{name:"Rate App",url:"menu-rate.html",menuID:4},
{name:"Report Bugs",url:"menu-bugs.html",menuID:5},
{name:"Settings",url:"menu-settings.html",menuID:6}
] ;
return {
all: function() {
return menus ;
},
get: function(menu) {
for (var i = 0; i < menus.length; i++) {
if (menus[i].menuID === parseInt(menuID)) {
return menus[i];
}
}
return null;
},
} ;
}) ;
In the above .state('tab.menu-detail'..., the templuateUrl function fires and the first console log entry works, the 2nd one does nothing, no message, no error...nothing. It just stops. I have tried multiple iterations to get this to work and am at a complete loss. When I click the above Tab page link (which is supposed to take you to a sub-custom view) it does nothing. No console message, no error...nothing.
You can assign function to template Url. I have faced the similar scenario following solution worked fine.
check this:
link

How to reset $stateparam parameter value to null in angularjs?

This is my code.
.state('appSetting.studentList', { url: '/student', views: { 'list#appSetting': { templateUrl: appUrl + '/Student/List', controller: 'StudentCtrl' } } })
.state('appSetting.studentList.details', { url: '/:studentId', views: { 'details#appSetting': { templateUrl: appUrl + '/Student/Edit', controller: 'StudentEditCtrl' } } })
.state('appSetting.employeeList', { url: '/employee', views: { 'list#appSetting': { templateUrl: appUrl + '/Employee/List', controller: 'EmployeeCtrl' } } })
.state('appSetting.employeeList.details', { url: '/:employeeId', views: { 'details#appSetting': { templateUrl: appUrl + '/Employee/Edit', controller: 'EmployeeEditCtrl' } } })
I have a add button on layout , when user click the add button call the following function.
$scope.gotoAdd = function () {
if ($state.current.name.indexOf(".details") == -1) {
$state.go($state.current.name + ".details")
}
else {
var paramId = $state.current.url.slice(2);
$state.go($state.current.name, ({ studentId: "", reload: true }));
}
};
In the above code working fine, but when open employee page user click add button i want to empty of employeeId parameter. I have number of links so if condition is using lengthy process. The above variable paramId dynamically changed (one time "studentId" , "employeeId" ,..............) depends on current state.
I tried the following code but not working because paramId contains string value
$state.go($state.current.name, ({ paramId: "", reload: true }));
Why are you putting the second parameter in '( )' in $state.go().
Try
$state.go($state.current.next, {}, {reload: true});
or
$state.go($state.current.next, {paramId: ""}, {reload: true});
$scope.gotoAdd = function () {
if ($state.current.name.indexOf(".details") == -1) {
$state.go($state.current.name + ".details")
}
else {
for (var prop in $stateParams) {
if ($stateParams.hasOwnProperty(prop)) {
$stateParams[prop] = '';
}
}
$state.go($state.current.name,$stateParams, { reload: true });
}
};
$state.go can take an inherit boolean parameter that serve exactly for this purpose.
As of UI router 0.2.15 -probably an old version, the documentation states
inherit - {boolean=true}, If true will inherit url parameters from current url.
In fact, it reset not only url parameters, but all $stateParams to their default, like what they are in state definition.
This will keep only state params as passed through the params object and all other are set to default or deleted.
$state.go('target.state', params, {inherit: false});

UI-Router's resolve functions are only called once- even with reload option

In Angular ui router, when $state.go("main.loadbalancer.readonly"); is ran after main.loadbalancer.readonly has been previously activated, my resolve: {} is not being evaulauted/executed. The resolve is simply bypassed..I have verified this with the console.log($state.current.data['deviceId']); not showing.
angular.module("main.loadbalancer", ["ui.bootstrap", "ui.router"]).config(function($stateProvider) {
return $stateProvider.state("main.loadbalancer", {
url: "device/:id",
views: {
"content#": {
templateUrl: "loadbalancer/loadbalancer.html",
controller: "LoadBalancerCtrl"
}
}
}).state("main.loadbalancer.vips", {
resolve: {
isDeviceReadOnly: function($state) {
console.log($state.current.data['deviceId']);
if (!$state.current.data['deviceId']) {
console.log("pimp");
$state.go("main.loadbalancer.readonly");
}
}
},
url: "/vips",
templateUrl: "loadbalancer/vip-table.html",
controller: "VipListCtrl"
}).state("main.loadbalancer.readonly", {
url: "/readonly",
templateUrl: "loadbalancer/readonly.html",
controller: "ReadonlyCtrl"
});
});
Controller code:
submit = function() {
$state.current.data = { deviceId: false };
return LoadBalancerSvc.searchDevice($scope.searchInput.value).get().then(function(lb) {
console.log(lb.ha_status);
if (lb.ha_status == "secondary") {
console.log("hi");
$state.current.data['deviceId'] = false;
$state.go("main.loadbalancer.readonly"); //WHEN THIS IS RAN A SECOND TIME
AFTER STATE HAS BEEN ACTIVE BEFORE
$state.deviceReadonly = true
} else {
$state.current.data['deviceId'] = lb.id;
$state.deviceReadonly = false;
SearchSvc.updateDeviceNumber(lb.id);
$state.go("main.loadbalancer.vips", {id: lb.id});
console.log("bye");
}
});
};
I can only guess that since main.loadbalancer.vips has been activated previously, then to ui router it means once resolved always resolved. How can I make it to where each time the state is activated with $state.go("main.loadbalancer.readonly") resolve will be evaluated?
Note: I have also tried $state.go("main.loadbalancer.readonly", { reload: true }); to no success.
It seems that 'transitionTo' works instead.
if (lb.ha_status == "secondary") {
$state.current.data['deviceId'] = false;
$state.transitionTo("main.loadbalancer.readonly", {}, { reload: true });
$state.deviceReadonly = true
}

how can I pass a service to a controller dynamically by some conditions

I am using the ui-router module and have defined these states:
.state('projects.create', {
url: '/create',
views: {
'outer#': {
templateUrl: 'views/projects.create.html',
resolve: {
schoolyear: function(schoolyearService) {
return schoolyearService.createSchoolyear();
}
},
controller: 'ProjectWizardController'
}
}
})
.state('projects.edit', {
url: '/edit',
views: {
'outer#': {
templateUrl: 'views/projects.edit.html',
resolve: {
schoolyear: function(schoolyearService) {
return schoolyearService.editSchoolyear();
}
},
controller: 'ProjectWizardController'
}
}
})
As each of both ui-router states know which states they are they also know what dependencies should be passed to the ProjectWizardController.
When the projects.create state is activated I want to pass the CreateWizardDataService to the ProjectWizardController.
When the projects.edit state is activated I want to pass the EditWizardDataService to the ProjectWizardController.
HOW can I manually inject the service dependency into the ProjectsWizardController?
'use strict';
angular.module('schoolyearProjectModule').controller('ProjectWizardController',
function ($scope, wizardDataService, $state, schoolyear) {
// wizardDataService => could be the CreateWizardDataService or EditWizardDataService
// The wizardDataService is the individual service for an AddService or EditService
// service contain the 3 same main properties: schoolyearData, schoolclasscodesData, timetableData
wizardDataService.schoolyearData = schoolyear.schoolyearData;
wizardDataService.schoolyearData = schoolyear.schoolclassCodesData;
wizardDataService.schoolyearData = schoolyear.timetableData;
// The if and else if should be injected into this Controller becaue the outside ui router states know their state edit/create
if ($state.current.name === 'projects.create') {
$scope.steps = [wizardDataService.schoolyearData, wizardDataService.schoolclassCodesData, wizardDataService.timetableData];
}
else if ($state.current.name === 'projects.edit') {
$scope.steps = [wizardDataService.schoolyearData, wizardDataService.schoolclassCodesData, wizardDataService.timetableData];
}
$scope.steps = [wizardDataService.schoolyearData, wizardDataService.schoolclassCodesData, wizardDataService.timetableData];
$scope.activeStep = $scope.steps[0];
$scope.step = 0;
var stepsLength = $scope.steps.length;
$scope.isLastStep = function () {
return $scope.step === (stepsLength - 1);
};
$scope.isFirstStep = function () {
return $scope.step === 0;
};
$scope.getCurrentStep = function () {
return $scope.activeStep.name;
};
$scope.getNextLabel = function () {
return ($scope.isLastStep()) ? 'Submit' : 'Next';
};
$scope.previous = function () {
if ($scope.step > 0) {
$scope.step--;
$scope.activeStep = $scope.steps[$scope.step];
}
};
$scope.next = function () {
if ($scope.isLastStep() && $scope.activeStep.isValid()) {
$state.go('^');
}
else if ($scope.activeStep.isValid()) {
$scope.step += 1;
$scope.activeStep = $scope.steps[$scope.step];
}
}
});
You have two ways to do this:
Option 1 - Use resolve with a string as the value. As per the documentation:
The resolve property is a map object. The map object contains
key/value pairs of:
key – {string}: a name of a dependency to be injected into the
controller.
factory - {string|function}: If string, then it is an
alias for a service. Otherwise if function, then it is injected and
the return value is treated as the dependency. If the result is a
promise, it is resolved before the controller is instantiated and its
value is injected into the controller.
Option 1 example:
.state('projects.create', {
url: '/create',
views: {
'outer#': {
templateUrl: 'views/projects.create.html',
resolve: {
schoolyear: function(schoolyearService) {
return schoolyearService.createSchoolyear();
},
wizardDataService: 'CreateWizardDataService'
},
controller: 'ProjectWizardController'
}
}
})
.state('projects.edit', {
url: '/edit',
views: {
'outer#': {
templateUrl: 'views/projects.edit.html',
resolve: {
schoolyear: function(schoolyearService) {
return schoolyearService.editSchoolyear();
},
wizardDataService: 'EditWizardDataService'
},
controller: 'ProjectWizardController'
}
}
})
Option 2 - Use $injector.get('CreateWizardDataService') or $injector.get('EditWizardDataService') directly in your controller depending on which state you are in.

Authorization Service fails on page refresh in angularjs

Implemented the authorization using the POST
The problem is when i go to a privileged page say '/admin' it works but when i refresh the page
manually, the admin page is redirecting to the '/unauthorized' page
Permissions service
angular.module('myApp')
.factory('PermissionsService', function ($rootScope,$http,CookieService) {
var permissionList;
return {
setPermissions: function(permissions) {
permissionList = permissions;
$rootScope.$broadcast('permissionsChanged')
},
getPermissions: function() {
var roleId = 5
if(CookieService.getLoginStatus())
var roleId = CookieService.getUserData().ROLE_ID;
return $http.post('api/user-permissions', roleId).then(function(result){
return result.data;
});
},
hasPermission: function (permission) {
permission = permission.trim();
return _.some(permissionList, function(item) {
if(_.isString(item.name))
return item.name.trim() === permission
});
}
};
});
hasPermissions directive
angular.module('myApp')
.directive('hasPermission', function(PermissionsService) {
return {
link: function(scope, element, attrs) {
if(!_.isString(attrs.hasPermission))
throw "hasPermission value must be a string";
var value = attrs.hasPermission.trim();
var notPermissionFlag = value[0] === '!';
if(notPermissionFlag) {
value = value.slice(1).trim();
}
function toggleVisibilityBasedOnPermission() {
var hasPermission = PermissionsService.hasPermission(value);
if(hasPermission && !notPermissionFlag || !hasPermission && notPermissionFlag)
element.show();
else
element.hide();
}
toggleVisibilityBasedOnPermission();
scope.$on('permissionsChanged', toggleVisibilityBasedOnPermission);
}
};
});
app.js
var myApp = angular.module('myApp',['ngRoute','ngCookies']);
myApp.config(function ($routeProvider,$httpProvider) {
$routeProvider
.when('/', {
templateUrl: 'app/module/public/index.html',
header: 'app/partials/header.html',
footer: 'app/partials/footer.html'
})
.when('/login', {
templateUrl: 'app/module/login/login.html',
header: 'app/partials/header.html',
footer: 'app/partials/footer.html'
})
.when('/home', {
templateUrl: 'app/module/home/home.html',
header: 'app/partials/header.html',
footer: 'app/partials/footer.html'
})
.when('/register', {
templateUrl: 'app/module/register/register.html',
header: 'app/partials/header.html',
footer: 'app/partials/footer.html'
})
.when('/admin', {
templateUrl: 'app/module/admin/admin.html',
header: 'app/partials/header.html',
footer: 'app/partials/footer.html',
permission: 'admin'
})
.when('/unauthorized', {
templateUrl: 'app/partials/unauthorized.html',
header: 'app/partials/header.html',
footer: 'app/partials/footer.html'
})
.otherwise({redirectTo: '/'});
$httpProvider.responseInterceptors.push('securityInterceptor');
});
myApp.provider('securityInterceptor', function() {
this.$get = function($location, $q) {
return function(promise) {
return promise.then(null, function(response) {
if(response.status === 403 || response.status === 401) {
$location.path('/unauthorized');
}
return $q.reject(response);
});
};
};
});
myApp.run(function($rootScope, $location, $window, $route, $cookieStore, CookieService, PermissionsService) {
PermissionsService.getPermissions().then(function(permissionList){
PermissionsService.setPermissions(permissionList);
});
// Check login status on route change start
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
if(!CookieService.getLoginStatus() && $location.path() != '/register' && $location.path() != '/login') {
$location.path("/");
$rootScope.$broadcast('notloggedin');
}
if(CookieService.getLoginStatus() && $location.path() == '/login') {
$location.path("/home");
}
var permission = next.$$route.permission;
if(_.isString(permission) && !PermissionsService.hasPermission(permission))
$location.path('/unauthorized');
});
// Adds Header and Footer on route change success
$rootScope.$on('$routeChangeSuccess', function (ev, current, prev) {
$rootScope.flexyLayout = function(partialName) { return current.$$route[partialName] };
});
});
CookieService
angular.module('myApp')
.factory('CookieService', function ($rootScope,$http,$cookieStore) {
var cookie = {
data: {
login: false,
user: undefined
},
saveLoginData: function(user) {
cookie.data.login = true;
cookie.data.user = user;
$cookieStore.put('__iQngcon',cookie.data);
},
deleteLoginData: function() {
cookie.data.login = false;
cookie.data.user = undefined;
$cookieStore.put('__iQngcon',cookie.data);
},
getLoginStatus: function() {
if($cookieStore.get('__iQngcon') === undefined)
return cookie.data.login;
return $cookieStore.get('__iQngcon').login;
},
getUserData: function() {
return $cookieStore.get('__iQngcon').user;
}
};
return cookie;
});
It seems like the permissions data are lost on page refresh. Is there any other way i can solve the problem? Or is there any problem with the code??
when i refresh the page manually, the admin page is redirecting to the
'/unauthorized' page
Isn't that expected behavior? If you reload the page; then all UI state is lost; it is just like shutting down the app and starting from scratch.
It seems like the permissions data are lost on page refresh. Is there
any other way i can solve the problem? Or is there any problem with
the code??
If you want to be able to retain UI state after a page reload, you'll have to retain the Login information somehow, such as in a browser cookies. When the app loads; check for that cookie value. If it exists, you can load the user info from the database, essentially mirroring a login.
I'd be cautious about storing actual user credentials in a cookie without some type of encryption.
One approach I've used is to store a unique user key which can be sent to the DB to load user info. Sometimes this may be a UUID associated with the user, Avoid using an auto-incrementing primary key because that is easy to change to get access to a different user's account.
Well had to think for some time and made the following change for it to work. It may not be the best practice but ya worked for me. Would appreciate if anyone suggested me a better solution in the comments if found.
myApp.run(function($rootScope, $location, $window, $route, $cookieStore, CookieService, PermissionsService) {
var permChanged = false;
PermissionsService.getPermissions().then(function(permissionList){
PermissionsService.setPermissions(permissionList);
});
// Check login status on route change start
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
console.log('$routeChangeStart');
if(!CookieService.getLoginStatus() && $location.path() != '/register' && $location.path() != '/login') {
$location.path("/");
$rootScope.$broadcast('notloggedin');
}
if(CookieService.getLoginStatus() && $location.path() == '/login') {
$location.path("/home");
}
$rootScope.$on('permissionsChanged', function (ev, current, prev) {
permChanged = true;
});
if(CookieService.getLoginStatus() && permChanged) {
var permission = next.$$route.permission;
if(_.isString(permission) && !PermissionsService.hasPermission(permission))
$location.path('/unauthorized');
}
});
// Adds Header and Footer on route change success
$rootScope.$on('$routeChangeSuccess', function (ev, current, prev) {
$rootScope.flexyLayout = function(partialName) { return current.$$route[partialName] };
});
});
What i did was wait for the permissions to be set and then use the permissionChanged broadcast to set a permChanged variable to true and then combined with if user loggedin status and permchanged had to check the permissions if had
$rootScope.$on('permissionsChanged', function (ev, current, prev) {
permChanged = true;
});
if(CookieService.getLoginStatus() && permChanged) {
var permission = next.$$route.permission;
if(_.isString(permission) && !PermissionsService.hasPermission(permission))
$location.path('/unauthorized');
}

Resources