is there using angularJS 1.5 and ui.router to define State and routes dynamically?
I mean getting the data from a backend sever and then populate the ui-router param such as state, URL ...
I tried to use the put them in the run part but it's not working as the data retrieved from the server wasn't available when needed. here is what I'm doing
run(
function run(Idle, $http, $q, $state, $rootScope) {
Idle.watch();
$urlRouterProviderRef.otherwise('/login');
$urlRouterProviderRef.when("", "/login");
$http.get(_contextPath + '/routing', {})
.success(function(data)
{
$rootScope.LOGIN_PAGE_CONTROLLER_NAME = data.LOGIN_PAGE_CONTROLLER_NAME;
$rootScope.LOGIN_PAGE_PAGE_TITLE = data.LOGIN_PAGE_PAGE_TITLE;
$rootScope.LOGIN_PAGE_STATE = data.LOGIN_PAGE_STATE;
$rootScope.LOGIN_PAGE_TEMPLATE_URL = data.LOGIN_PAGE_TEMPLATE_URL;
$rootScope.LOGIN_PAGE_URL = data.LOGIN_PAGE_URL;
});
var test = $rootScope.LOGIN_PAGE_STATE;
$stateProviderRef.state($rootScope.LOGIN_PAGE_STATE, {
url : $rootScope.LOGIN_PAGE_URL,
views : {
"mainbody" : {
templateUrl : $rootScope.LOGIN_PAGE_TEMPLATE_URL
},
},
controller : $rootScope.LOGIN_PAGE_CONTROLLER_NAME,
data : {
pageTitle : $rootScope.LOGIN_PAGE_PAGE_TITLE,
authenticate : false
}
});
})
any help is really apreciated
The way to go is described here
AngularJS - UI-router - How to configure dynamic views
A code snippet:
var app = angular.module('app', ['ui.router.router']);
app.config(function($urlRouterProvider) {
// Prevent $urlRouter from automatically intercepting URL changes;
// this allows you to configure custom behavior in between
// location changes and route synchronization:
$urlRouterProvider.deferIntercept();
}).run(function($rootScope, $urlRouter, UserService) {
$rootScope.$on('$locationChangeSuccess', function(e) {
// UserService is an example service for managing user state
if (UserService.isLoggedIn()) return;
// Prevent $urlRouter's default handler from firing
e.preventDefault();
UserService.handleLogin().then(function() {
// Once the user has logged in, sync the current URL
// to the router:
$urlRouter.sync();
});
});
// Configures $urlRouter's listener *after* your custom listener
$urlRouter.listen();
});
Check more and working plunker there
Related
I'm trying to build a single page node/angular ( v 1.56 ) application that leverages angular's ui-router to change pages inside the application without having any browser reloads. My main obstacle is that I'm trying to figure out how, after a successful login event, do I get the user to the dashboard page without having to redirect/reload that page? Ideally, I'm looking for a way to programmatically trigger a route just as if I had clicked on the link.
I tried using angular's $http.get('/dashboard') to the target route after the loginAction post response, but this doesn't work, as $http.get() is quite different than a GET call that results from actually clicking on an href="/dashboard" anchor tag. The latter click event calls the dashboard page as it should, rendering it in the tag on the index page. Is there a 'graceful', angular way to handle this ? This issue is the same using node's express webserver or a custom webserver that leverages filestreams.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script>
var app = angular.module('myApp',['ui.router']);
app.config(function($stateProvider) {
var aboutState = {
name: 'about', //for testing
templateUrl: '/about'
};
var dashboardState = {
name: 'dashboard',
templateUrl: '/dashboard'
};
$stateProvider.state(aboutState);
$stateProvider.state(dashboardState);
});
controller
app.controller("myCtrl", function($scope, $http) {
$scope.userMessage = "";
$scope.loginSubmit = function () {
$scope.userMessage = "Submitting...";
$http.post("/loginAction",{ 'username': $scope.username, 'password':$scope.password }).then(function(response) {
if( response.data.loginStatus == 'Authenticated' && response.data.userType != '' ) {
// OK ! - we're free to go to the dashboard page now. But how ?
// I could do: document.querySelector("#dash").click();
// this works, but this doesn't seem very secure
// The following doesn't work:
$http.get("/dashboard").then(function( response ) {
// Why doesn't the above '/dashboard' route , but
// clicking on something like Dashboard actually works ?
// Short of taking the dashboard html in the response and using bind-html to force it
// into the dom, is there a better solution to avoid a window.location reload here ?
$scope.userMessage = "Login Successful";
});
}
});
}
});
I think I answered my own question. I needed to leverage the 'ngRoute' service and inject $location into my controller like so:
<script>
var app = angular.module('myApp',['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl : 'login',
controller : 'myCtrl'
})
.when('/test', {
templateUrl : '/test',
controller : 'myCtrl'
})
.when('/dashboard', {
templateUrl :'/dashboard',
controller : 'myCtrl'
}).otherwise({redirectTo: '/'});
});
app.controller("myCtrl", function( $scope, $http, $location ) {
$scope.userMessage = "";
// fire this function upon successful login:
$scope.changeRoute = function( route ) {
$location.path( route );
}
$scope.loginSubmit = function () {
$scope.userMessage = "Submitting...";
$http.post("/loginAction",{ 'username': $scope.username, 'password':$scope.password }).then(function(response) {
if( response.data.loginStatus == 'Authenticated' && response.data.userType != '' ) {
$scope.userMessage = "Authenticated...";
$scope.changeRoute( response.data.destination_route );
}
});
}
});
I have created an application that loads routes dynamically and in turn there controllers.
My controllers are added using an ng-repeat in my index file and then bootstrapped manually.
The issue i have is when i refresh, sometimes my routing loads and attempts to redirect to a given route before its controller is loaded.
My question is, is there a way to detect if a controller is loaded using some kind of event?
Dynamically load my controllers:
<script ng-repeat="script in clientScripts" ng-src="{{script}}"></script>
Manually bootstrap the controllers
app.config(function($provide, $compileProvider, $controllerProvider, $routeProvider, $httpProvider, uiGmapGoogleMapApiProvider, $injector, toastrConfig, constant) {
app.$$registerFactory = $provide.factory;
app.$$registerService = $provide.service;
app.$$registerCtrl = $controllerProvider.register;
app.$$routeProviderRef = $routeProvider;
app.$$httpProviderRef = $httpProvider;
app.$$registerDirective = $compileProvider.directive;
...
...
Initialize my controller
app.$$registerCtrl('AchievementsController', AchievementsController);
Dynamically load my routes
/*
// DYNAMIC CLIENT ROUTING
// ======================
// corresponding controllers and factories need
// to be added in the client config.json
*/
$rootScope.$watch('config', function(x, y, z) {
if ($rootScope.config) {
// get route json and start adding routes
$http.get('../content/' + $rootScope.config.contentFolder + '/config/route.json').then(function(response) {
angular.forEach(response.data, function(value) {
// Add routes from client route.json
angular.module('dashboard').$$routeProviderRef.when(value.route, {
caseInsensitiveMatch: value.vars.caseInsensitiveMatch,
templateUrl: value.vars.templateUrl,
resolve: {
auth: function(AuthFactory) {
return value.requiresAuthentication === true ? AuthFactory.IsAuthenticated() : AuthFactory.IsAnnonymous();
}
}
});
});
var route = SessionStorage.getObject('route');
if (route && $route.current.originalPath != route && route != '/dashboard') {
$location.path(route);
}
});
}
});
After login I want to pass the user details to dashboard?How it possible in angular js?
Login.js
mySchoolApp.controller('loginController', ['$scope', '$http', function($scope, $http) {
this.loginForm = function() {
let encodedString = 'uname=' +this.username +'&pwrd=' +this.password;
sessionStorage.user = encodedString;
console.log(sessionStorage.user)
window.location.href = 'dashboard.html';
}
}]);
In console I'm getting the value.
How to get the user details in dashboard.html page?
You should use ng-route to achieve this.Angular isn't designed to work like this
Here is sample
$stateProvider
.state('app', {
abstract: true,
url: "",
template: '<ui-view/>'
})
.state('app.home', {
url: "/",
templateUrl: "partials/main_page.html",
resolve: {
skipIfLoggedIn: skipIfLoggedIn
}
}).state('app.dashboard', {
url: "/dashboard",
templateUrl: "partials/dashboard.html",
controller: 'DashboardCtrl',
activePage:'dashboard',
resolve: {
loginRequired: loginRequired
}
You can store it in a localstorage.So you can use angular-local-storage Angular module for that.
How to set :
myApp.controller('MainCtrl', function($scope, localStorageService) {
//...
function submit(key, val) {
return localStorageService.set(key, val);
}
//...
});
How to Get :
myApp.controller('MainCtrl', function($scope, localStorageService) {
//...
function getItem(key) {
return localStorageService.get(key);
}
//...
});
You should use router module ui-router or ng-router in order to use angualrjs logic in that sense but then your pages are going to be loaded via ajax and regular session http authentication can not be applied.
If that's the case then use angular service provider and let me know to edit my answer.
If you'd like to keep data across pages and not using database or server.
Then what is left as options are: sessionStorage and localStorage.
The localStorage keeps data permanently until browser cache deletes it while the other one obviously for the session.
sessionStorage.setItem('myCat', 'Tom');
If you want to keep js collection like object or array first stringify it:
var user = {pass:'moo', name: 'boo'};
sessionStorage.setItem('userDetais', JSON.stringify(user));
This is my LoginController, as you can see I have injected the LoginService, I can't seem to figure out why I am getting the error mentioned above (Note: I've made the project modular by breaking my project in separates folder, using gulp and browserify to bundle everything into one file)
'use strict';
function LoginController($scope, $ionicModal, $timeout, $location,
$ionicLoading, $ionicPopup, LoginService) {
// With the new view caching in Ionic, Controllers are only called
// when they are recreated or on app start, instead of every page change.
// To listen for when this page is active (for example, to refresh data),
// listen for the $ionicView.enter event:
//$scope.$on('$ionicView.enter', function(e) {
//});
// Form data for the login modal
$scope.loginData = {};
// Create the login modal that we will use later
$ionicModal.fromTemplateUrl('js/modules/login/login.html', {
scope: $scope
}).then(function(modal) {
$scope.modal = modal;
});
// Triggered in the login modal to close it
$scope.closeLogin = function() {
$scope.modal.hide();
};
// Open the login modal
$scope.login = function() {
$scope.modal.show();
};
$scope.show = function() {
$ionicLoading.show({
template:'<p>Loading...</p><ion-spinner></ion-spinner>'
});
};
$scope.hide = function(){
$ionicLoading.hide();
};
// Perform the login action when the user submits the login form
$scope.doLogin = function() {
console.log('Doing login', $scope.loginData);
// Start showing the progress
$scope.show($ionicLoading);
// Do the call to a service using $http or directly do the call here
LoginService.login($scope.loginData).success(function(data) {
// Do something on success for example if you are doing a login
console.log('Login successful', data);
}).error(function(data) {
// Do something on error
console.log('Login failed', data);
}).finally(function($ionicLoading) {
// On both cases hide the loading
console.log('Hide');
$scope.hide($ionicLoading);
});
};
}
module.exports = ['$scope', '$ionicModal', '$timeout','$location',
'$ionicLoading','LoginService','$ionicPopup',
LoginController];
This is my LoginService file, this is very weird to me because I've injected the appropriate file but yet I keep getting the error mentioned above. Any help or guidance would deeply be appreciated.
'use strict';
function LoginService($http, $q, API_ENDPOINT) {
var BASE_URL = API_ENDPOINT.url;
var LOCAL_TOKEN_KEY = 'yourTokenKey';
var isAuthenticated = false;
var authToken;
function storeUserCredentials(token) {
window.localStorage.setItem(LOCAL_TOKEN_KEY, token);
useCredentials(token);
}
function useCredentials(token) {
isAuthenticated = true;
authToken = token;
// Set the token as header for your requests!x-access-token'
$http.defaults.headers.common.Authorization = authToken;
}
var login = function(user) {
return $q(function(resolve, reject) {
$http.post(BASE_URL + '/authenticate', user).then(function(result){
if (result.data.success) {
storeUserCredentials(result.data.token);
resolve(result.data.msg);
}else{
reject(result.data.msg);
}
});
});
};
return {
login: login,
isAuthenticated: function() {return isAuthenticated;},
};
}
module.exports = ['$http', '$q', 'API_ENDPOINT', LoginService];
This is my login.js file in the same directory as the one posted above
'use strict';
module.exports = angular.module('login', [])
.factory('LoginService', require('./login-service'))
.controller('LoginController', require('./login-controller'));
You should first do require and then only define the service. Since you are directly passing require in the .factory('LoginServie, require()` the service name is getting registered but its body is empty.
I've not worked much with require but here is you can try:
require('./login-service');
module.exports = angular.module('login', [])
// Make this code synchornous that this should only run when above require loaded the script
.factory('LoginService', LoginService)
.controller('LoginController', require('./login-controller'));
Or (probably)
require('./login-service', function() {
module.exports = angular.module('login', [])
.factory('LoginService', LoginService)
.controller('LoginController', require('./login-controller'));
})
When using a factory you are getting the actual class, and you need to instantiate it. When using a service you get an instance of the service. Take a look at the following example: AngularJS : Factory and Service?
I am developing an application with angularjs what I need to do is to basically run some scripts when route is changed to a specific route I know that I can define a separate controller for each route. since, some routs are supposed to have shared data I shared a controller to between some of them
formApp.config(function($routeProvider) {
$routeProvider
.when('/firstUrl',{
templateUrl : 'firstURL',
controller : 'mainController'
})
.when('/secondURL' , {
templateUrl : 'secondURL',
controller : 'mainController'
})
}).run(function($rootScope, $location) {
$rootScope.$on("$routeChangeStart", function(event, next, current) {
if ( signed_in == false ) {
$location.path("/login");
}
});
});
The above is my config code,
MY QUESTION : I need to know if I can modify the code in the run() function, so that based on the route which user is redirected to some scripts are run.
or if this is not the right way to do that please correct me how do I have to solve this issue?
thanks in advance
I would recommend to create at least one controller per route. It makes the code more manageble.
Then you can define an init function that runs when each controller loads.
To share data between controllers you need to create a service, which is the correct way to do it rather then sharing the same controller for multiple paths.
It will also give you way more flexibilitywhen developing.
Update
Example
( Naming for example purposes only. Try to never do arrbitrary naming. )
#Service
angular.module('myService', [])
.factory('mSrv',[ function() {
return {
data: {
'first_name': 'John',
'last_name': 'Doe'
}
};
}])
;
#Controller1
angular.module('initMyCtrl1', ['myService'])
.controller('InitMyCtrl1', function( $scope, mSrv ) {
var initMyCtrl1 = function(){
console.log('runs on controller load')
console.log(mSrv.data);
};
initMyCtrl1();
})
;
#Controller2
angular.module('initMyCtrl2', ['myService'])
.controller('InitMyCtrl2', function( $scope, mSrv ) {
var initMyCtrl2 = function(){
console.log('runs on controller load')
console.log(mSrv.data);
};
initMyCtrl2();
})
;