How i check if a dynamically loaded Angular Controller has been regestered - javascript

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);
}
});
}
});

Related

Handling successful node/angularjs login without reloading page

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 );
}
});
}
});

angular js : Is it necessary to load all the controllers and factories / services in module file

NET MVC to one CRM application and using angular js for client side script.
I have come across several articles to use angular js and all of them have set controller and services / factories inside the module and they are loaded all in one time.
So my question is it necessary to load all controllers and services in module or I can separate those js and use in page by page whenever I need to use page wise?
I am navigating using ASP.NET MVC pattern not single page using angularjs route.
Yes you can separate those angularjs files and use one angularjs controller per page, but you need to register the modulename of the controller or service in the main module(app.js) inside the brackets[], like this:
//app.js
var app = angular.module('myApp', ['ngRoute','myApp.controller','myApp.create.controller'])
.config(function ($routeProvider,$locationProvider) {
$routeProvider
.when("/", {
templateUrl: 'home/home.html',
controller: 'HomeController',
controllerAs: 'home'
}).when("/create",{
templateUrl: 'manage/create.html',
controller: 'CreateController',
controllerAs: 'create'
})
});
//HomeController.js
var module = angular.module('myApp.controller', ['myApp.service']);
module.controller('HomeController', ['HomeService',
function (HomeService) {
var self = this;
self.EmpData = [];
HomeService.getAllEmployeesTable().then(onSuccess, onError);
function onSuccess(response) {
self.EmpData = response.data;
}
function onError(error) {
alert('Error fetching data');
}
}]);
//CreateController.js
var module = angular.module('myApp.create.controller',['myApp.create.service']);
module.controller('CreateController',['CreateService',
function(CreateService){
var self =this;
self.person = {
name : "", email:"",address:"",telephone:""
}
self.submitPerson = function(){
console.log(self.person);
CreateService.submitPerson(self.person).then(onSuccess,onError);
}
var onSuccess = function(response){
alert("User has been added succesffully");
}
var onError = function(error){
alert("Error creating person");
}
}
]);

ui-router Dynamic routing issue

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

how to check firebase auth before routeProvider send to page

I want a route to check and see if a Firebase user is signed in before it redirects someone to the /map.html page.
.when('/map', {
templateUrl: 'views/map.html',
controller: 'MapCtrl',
resolve: {
loggedIn: onlyLoggedIn()
}
});
I have tried using resolve (see code above) but I only get errors from the onlyLoggedIn() function that say "user is not defined". User is defined and if I try to pass in user to the function I get an error "Unknown provider: user"
var onlyLoggedIn = function ($location,$q,user) {
var deferred = $q.defer();
console.log("well: "+user);
if (user) {
console.log("user is signed in ");
deferred.resolve();
} else {
deferred.reject();
$location.url('/signup');
}
return deferred.promise;
};
How should I go about checking if a user is signed in with firebase before routing them to the /map page?
Firebase gives me the user variable and in 'other' places in my app it works, so the problem isn't user not being defined, but my onlyLoggedIn function not "getting" it(?)
Security rules in Firebase can prevent the page from data from being viewed without permission. You need a client-side solution to redirect the page. You do in routes.
This is complete code for the Angular Firebase
This is simple code demonstration. I hope that will work for you.
angular.module('myApp.routes', ['ngRoute', 'simpleLogin'])
.constant('ROUTES', {
'/home': {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl',
resolve: {
// forces the page to wait for this promise to resolve before controller is loaded
// the controller can then inject `user` as a dependency. This could also be done
// in the controller, but this makes things cleaner (controller doesn't need to worry
// about auth status or timing of displaying its UI components)
user: ['simpleLogin', function(simpleLogin) {
return simpleLogin.getUser();
}]
}
},
'/chat': {
templateUrl: 'partials/chat.html',
controller: 'ChatCtrl'
},
'/login': {
templateUrl: 'partials/login.html',
controller: 'LoginCtrl'
},
'/account': {
templateUrl: 'partials/account.html',
controller: 'AccountCtrl',
// require user to be logged in to view this route
// the whenAuthenticated method below will resolve the current user
// before this controller loads and redirect if necessary
authRequired: true
}
})
/**
* Adds a special `whenAuthenticated` method onto $routeProvider. This special method,
* when called, invokes the requireUser() service (see simpleLogin.js).
*
* The promise either resolves to the authenticated user object and makes it available to
* dependency injection (see AuthCtrl), or rejects the promise if user is not logged in,
* forcing a redirect to the /login page
*/
.config(['$routeProvider', function($routeProvider) {
// credits for this idea: https://groups.google.com/forum/#!msg/angular/dPr9BpIZID0/MgWVluo_Tg8J
// unfortunately, a decorator cannot be use here because they are not applied until after
// the .config calls resolve, so they can't be used during route configuration, so we have
// to hack it directly onto the $routeProvider object
$routeProvider.whenAuthenticated = function(path, route) {
route.resolve = route.resolve || {};
route.resolve.user = ['requireUser', function(requireUser) {
return requireUser();
}];
$routeProvider.when(path, route);
}
}])
// configure views; the authRequired parameter is used for specifying pages
// which should only be available while logged in
.config(['$routeProvider', 'ROUTES', function($routeProvider, ROUTES) {
angular.forEach(ROUTES, function(route, path) {
if( route.authRequired ) {
// adds a {resolve: user: {...}} promise which is rejected if
// the user is not authenticated or fulfills with the user object
// on success (the user object is then available to dependency injection)
$routeProvider.whenAuthenticated(path, route);
}
else {
// all other routes are added normally
$routeProvider.when(path, route);
}
});
// routes which are not in our map are redirected to /home
$routeProvider.otherwise({redirectTo: '/home'});
}])
/**
* Apply some route security. Any route's resolve method can reject the promise with
* { authRequired: true } to force a redirect. This method enforces that and also watches
* for changes in auth status which might require us to navigate away from a path
* that we can no longer view.
*/
.run(['$rootScope', '$location', 'simpleLogin', 'ROUTES', 'loginRedirectPath',
function($rootScope, $location, simpleLogin, ROUTES, loginRedirectPath) {
// watch for login status changes and redirect if appropriate
simpleLogin.watch(check, $rootScope);
// some of our routes may reject resolve promises with the special {authRequired: true} error
// this redirects to the login page whenever that is encountered
$rootScope.$on("$routeChangeError", function(e, next, prev, err) {
if( angular.isObject(err) && err.authRequired ) {
$location.path(loginRedirectPath);
}
});
function check(user) {
if( !user && authRequired($location.path()) ) {
$location.path(loginRedirectPath);
}
}
function authRequired(path) {
return ROUTES.hasOwnProperty(path) && ROUTES[path].authRequired;
}
}
]);

Can $routeProvider be replaced by $stateProvider or vice versa and how?

I have found a perfectly working and advanced Angularfire-Seed (that encompasses Simple Login). This framework uses ngRoute and $routeProvider to route the appropriate view and to make sure that certain pages are only shown when the user has logged in.
Now I want to integrate this with the Ionic Framework, such that I have an Ionic App that uses this Authentication system. However, Ionic uses $stateProvider.
My question then becomes: how do I combine these two? I guess one of the two has to go and be replaced by the other. But how do you do this?
Below are the two projects that I want to combine:
1. Angular-Fire Seed using $routeProvider (routes.js)
"use strict";
angular.module('myApp.routes', ['ngRoute', 'simpleLogin'])
.constant('ROUTES', {
'/home': {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl',
resolve: {
// forces the page to wait for this promise to resolve before controller is loaded
// the controller can then inject `user` as a dependency. This could also be done
// in the controller, but this makes things cleaner (controller doesn't need to worry
// about auth status or timing of displaying its UI components)
user: ['simpleLogin', function(simpleLogin) {
return simpleLogin.getUser();
}]
}
},
'/chat': {
templateUrl: 'partials/chat.html',
controller: 'ChatCtrl'
},
'/login': {
templateUrl: 'partials/login.html',
controller: 'LoginCtrl'
},
'/account': {
templateUrl: 'partials/account.html',
controller: 'AccountCtrl',
// require user to be logged in to view this route
// the whenAuthenticated method below will resolve the current user
// before this controller loads and redirect if necessary
authRequired: true
}
})
/**
* Adds a special `whenAuthenticated` method onto $routeProvider. This special method,
* when called, invokes the requireUser() service (see simpleLogin.js).
*
* The promise either resolves to the authenticated user object and makes it available to
* dependency injection (see AuthCtrl), or rejects the promise if user is not logged in,
* forcing a redirect to the /login page
*/
.config(['$routeProvider', function($routeProvider) {
// credits for this idea: https://groups.google.com/forum/#!msg/angular/dPr9BpIZID0/MgWVluo_Tg8J
// unfortunately, a decorator cannot be use here because they are not applied until after
// the .config calls resolve, so they can't be used during route configuration, so we have
// to hack it directly onto the $routeProvider object
$routeProvider.whenAuthenticated = function(path, route) {
route.resolve = route.resolve || {};
route.resolve.user = ['requireUser', function(requireUser) {
return requireUser();
}];
$routeProvider.when(path, route);
}
}])
// configure views; the authRequired parameter is used for specifying pages
// which should only be available while logged in
.config(['$routeProvider', 'ROUTES', function($routeProvider, ROUTES) {
angular.forEach(ROUTES, function(route, path) {
if( route.authRequired ) {
// adds a {resolve: user: {...}} promise which is rejected if
// the user is not authenticated or fulfills with the user object
// on success (the user object is then available to dependency injection)
$routeProvider.whenAuthenticated(path, route);
}
else {
// all other routes are added normally
$routeProvider.when(path, route);
}
});
// routes which are not in our map are redirected to /home
$routeProvider.otherwise({redirectTo: '/home'});
}])
/**
* Apply some route security. Any route's resolve method can reject the promise with
* { authRequired: true } to force a redirect. This method enforces that and also watches
* for changes in auth status which might require us to navigate away from a path
* that we can no longer view.
*/
.run(['$rootScope', '$location', 'simpleLogin', 'ROUTES', 'loginRedirectPath',
function($rootScope, $location, simpleLogin, ROUTES, loginRedirectPath) {
// watch for login status changes and redirect if appropriate
simpleLogin.watch(check, $rootScope);
// some of our routes may reject resolve promises with the special {authRequired: true} error
// this redirects to the login page whenever that is encountered
$rootScope.$on("$routeChangeError", function(e, next, prev, err) {
if( angular.isObject(err) && err.authRequired ) {
$location.path(loginRedirectPath);
}
});
function check(user) {
// used by the changeEmail functionality so the user
// isn't redirected to the login screen while we switch
// out the accounts (see changeEmail.js)
if( $rootScope.authChangeInProgress ) { return; }
if( !user && authRequired($location.path()) ) {
$location.path(loginRedirectPath);
}
}
function authRequired(path) {
return ROUTES.hasOwnProperty(path) && ROUTES[path].authRequired;
}
}
]);
2. Ionic Framework (app.js)
// Ionic Starter App
// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'starter.controllers', 'starter.services', 'ngCordova', 'firebase'])
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if (window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if (window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleDefault();
}
});
})
.config(function($stateProvider, $urlRouterProvider) {
// Ionic uses AngularUI Router which uses the concept of states
// Learn more here: https://github.com/angular-ui/ui-router
// Set up the various states which the app can be in.
// Each state's controller can be found in controllers.js
$stateProvider
// setup an abstract state for the tabs directive
.state('tab', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html"
})
// Each tab has its own nav history stack:
.state('tab.chats', {
url: '/chats',
views: {
'tab-chats': {
templateUrl: 'templates/tab-chats.html',
controller: 'ChatsCtrl'
}
}
})
.state('tab.account', {
url: '/account',
views: {
'tab-account': {
templateUrl: 'templates/tab-account.html',
controller: 'AccountCtrl'
}
}
})
.state('tab.login', {
url: '/login',
views: {
'tab-login': {
templateUrl: 'templates/tab-login.html',
controller: 'LoginCtrl'
}
}
});
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/tab/dash');
})
Update (16/01/2015, 10.46)
I have tried the following (replacing routeProvider by urlRouterProvider), it didnt work (nothing is showing up)
index.html, included:
<ion-nav-view></ion-nav-view>
routes.js
"use strict";
angular.module('myApp.routes', ['ngRoute', 'simpleLogin'])
.constant('ROUTES', {
'/home': {
templateUrl: 'templates/home.html',
controller: 'HomeCtrl',
resolve: {
// forces the page to wait for this promise to resolve before controller is loaded
// the controller can then inject `user` as a dependency. This could also be done
// in the controller, but this makes things cleaner (controller doesn't need to worry
// about auth status or timing of displaying its UI components)
user: ['simpleLogin', function(simpleLogin) {
return simpleLogin.getUser();
}]
},
authRequired: true
},
'/chat': {
templateUrl: 'templates/chat.html',
controller: 'ChatCtrl',
authRequired: true
},
'/camera': {
templateUrl: 'templates/camera.html',
controller: 'CameraCtrl',
authRequired: true
},
'/login': {
templateUrl: 'templates/login.html',
controller: 'LoginCtrl'
},
'/account': {
templateUrl: 'templates/account.html',
controller: 'AccountCtrl',
// require user to be logged in to view this route
// the whenAuthenticated method below will resolve the current user
// before this controller loads and redirect if necessary
authRequired: true
}
})
/**
* Adds a special `whenAuthenticated` method onto $routeProvider. This special method,
* when called, invokes the requireUser() service (see simpleLogin.js).
*
* The promise either resolves to the authenticated user object and makes it available to
* dependency injection (see AuthCtrl), or rejects the promise if user is not logged in,
* forcing a redirect to the /login page
*/
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
// credits for this idea: https://groups.google.com/forum/#!msg/angular/dPr9BpIZID0/MgWVluo_Tg8J
// unfortunately, a decorator cannot be use here because they are not applied until after
// the .config calls resolve, so they can't be used during route configuration, so we have
// to hack it directly onto the $routeProvider object
$urlRouterProvider.whenAuthenticated = function(path, route) {
route.resolve = route.resolve || {};
route.resolve.user = ['requireUser', function(requireUser) {
return requireUser();
}];
$urlRouterProvider.when(path, route);
}
}])
// configure views; the authRequired parameter is used for specifying pages
// which should only be available while logged in
.config(['$stateProvider', '$urlRouterProvider', 'ROUTES', function($stateProvider, $urlRouterProvider, ROUTES) {
angular.forEach(ROUTES, function(route, path) {
if( route.authRequired ) {
// adds a {resolve: user: {...}} promise which is rejected if
// the user is not authenticated or fulfills with the user object
// on success (the user object is then available to dependency injection)
$urlRouterProvider.whenAuthenticated(path, route);
}
else {
// all other routes are added normally
$urlRouterProvider.when(path, route);
}
});
// routes which are not in our map are redirected to /home
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/tab/dash');
}])
/**
* Apply some route security. Any route's resolve method can reject the promise with
* { authRequired: true } to force a redirect. This method enforces that and also watches
* for changes in auth status which might require us to navigate away from a path
* that we can no longer view.
*/
.run(['$rootScope', '$location', 'simpleLogin', 'ROUTES', 'loginRedirectPath',
function($rootScope, $location, simpleLogin, ROUTES, loginRedirectPath) {
// watch for login status changes and redirect if appropriate
simpleLogin.watch(check, $rootScope);
// some of our routes may reject resolve promises with the special {authRequired: true} error
// this redirects to the login page whenever that is encountered
$rootScope.$on("$stateChangeError", function(e, next, prev, err) {
if( angular.isObject(err) && err.authRequired ) {
$location.path(loginRedirectPath);
}
});
function check(user) {
// used by the changeEmail functionality so the user
// isn't redirected to the login screen while we switch
// out the accounts (see changeEmail.js)
if( $rootScope.authChangeInProgress ) { return; }
if( !user && authRequired($location.path()) ) {
$location.path(loginRedirectPath);
}
}
function authRequired(path) {
return ROUTES.hasOwnProperty(path) && ROUTES[path].authRequired;
}
}
]);

Categories