When starting out on my AngularJS journey, I couldn't get a good handle on the router native to the framework. So I adopted the use of the wonderful angular-ui / ui-router. During the past few years of development, I've honed in (for better or worse) my paradigm for setting new applications and nearly every AngularJS app has a routes.js file.
Without going into background, I wanted a way to load the ui-router dynamically. Typically, the routes gets defined in a .js file and typically looks something like this:
I thought it would be cool if I could somehow dynamically load the router via a JSON file produced from a database. This would allow, over time, the root application to become more standardized yet flexible when delivering routes to the end user.
My first step was to set up a data table to the routing information. This table contains information for both the router and the menu system. Each record in the table represents a route for a specific application in the overarching framework. In this case, a Function is equivalent to application.
The fields that will be utilized for the dynamic loading are:
Once the frameDataService.call returns, I loop over the results. Keep in mind that I massage the route properties from their respective database names.
The next step, after the _state is defined, is to register the _state by using the $stateRegistery.register function. The final step is to navigate to the ROOT route. This is in lieu of setting the $urlProvider.otherwise property which I haven't figured out to do yet.
So that's it in a nutshell. Get a JSON list of the routes; iterate through building a state object for each route; and then registering each state.
Just as a note: You'll see additional properties defined in the _state that are not actually part of the ui-router. These properties are used later in the framework to help standardize the look and feel of the content.
Hope this wasn't too confusing. As time permits, I may add some clarity later.
Cheers!
Without going into background, I wanted a way to load the ui-router dynamically. Typically, the routes gets defined in a .js file and typically looks something like this:
angular.module('core').config(function($stateProvider, $urlRouterProvider) { $urlRouterProvider.otherwise("/landing/201820"); $stateProvider .state('landing', {url: "/landing/:term", templateUrl: "apps/noted/templates/landing.html"}) .state('uploadCalendar', {url: "/uploadCalendar", templateUrl: "apps/noted/templates/uploadCalendar.html"}) .state('noteTakers', {url: "/noteTakers", templateUrl: "apps/noted/templates/notetakers.html"}) .state('noteReceivers', {url: "/noteReceivers", templateUrl: "apps/noted/templates/notereceivers.html"}) .state('studentAssignments', {url: "/studentAssignments", templateUrl: "apps/noted/templates/studentAssignments.html"}) });
I thought it would be cool if I could somehow dynamically load the router via a JSON file produced from a database. This would allow, over time, the root application to become more standardized yet flexible when delivering routes to the end user.
My first step was to set up a data table to the routing information. This table contains information for both the router and the menu system. Each record in the table represents a route for a specific application in the overarching framework. In this case, a Function is equivalent to application.
The fields that will be utilized for the dynamic loading are:
- Function ID - determines the application to load
- ROUTE_NAME - name of the route
- URL - url of the route as it appears in the browser
- TEMPLATE_URL - path to the HTML template of the route
- CONTROLLER - path to the controller's Javascript file for the given template/route
The FrameController is doing a few more things than just loading the routes. The first part of the code sets $rootScope state variables because I am going to need the routing information for the frame template and I wanted a quick and easy way to reference $state values.
The controller dependencies are as follows:
The $scope.goto function is just a quick way to navigate to the default route after routes have been loaded.
The controller dependencies are as follows:
- $rootScope, $scope
- $ocLazyLoad - needed to lazyLoad the controller Javascript
- $state, $stateParams
- $stateRegistry - this is the key dependency to registering the state
- frameDataService - interface to the database
The $scope.goto function is just a quick way to navigate to the default route after routes have been loaded.
angular.module('core').controller('FrameController', function($rootScope, $ocLazyLoad, $scope, $timeout, $state,$stateParams, $stateRegistry, frameDataService){ $rootScope.$state = $state; $rootScope.$stateParams = $stateParams; $scope.getUrlParameter = function(sParam) { var sPageURL = decodeURI(window.location.search.substring(1)); var sURLVariables = sPageURL.split('&'); for (var i = 0; i < sURLVariables.length; i++) { var sParameterName = sURLVariables[i].split('='); if (sParameterName[0] == sParam) { return sParameterName[1]; } } } $scope.goto = function(_route, _params){ console.log(_route); console.log(_params) $state.go(_route, _params); } frameDataService.call('getFunctionRoutes&_f=' + $scope.getUrlParameter('f')).then(function(data){ $scope.routes = data.data; for (var i=0; i < $scope.routes.length; i++){ console.log( $scope.routes[i]) if ( $scope.routes[i].name.length == 0){ $ocLazyLoad.load([$scope.routes[i].controller]); } if ( $scope.routes[i].name.length > 0){ var _state = { name: $scope.routes[i].name, url: $scope.routes[i].url, templateUrl: $scope.routes[i].templateUrl, icon: $scope.routes[i].icon, displayName: $scope.routes[i].displayName, instructions: $scope.routes[i].instructions, c: $scope.routes[i].controller , lazyLoad : function($transition$,_controller){ return $transition$.injector().get('$ocLazyLoad').load(_controller.c); } } $stateRegistry.register(_state) if ($scope.routes[i].status == 'ROOT'){ $scope.goto($scope.routes[i].defaultRoute,JSON.parse($scope.routes[i].defaultParams)); } } } }) });But the intended core of this post revolves around the next section of code: frameDataService.call(). frameDataService is a simple service that uses the $http functionality of AngularJS to query that database via Coldfusion. The end result is a data that is in JSON format - so it really doesn't matter what is used. A sample of the data looks like the following:
Once the frameDataService.call returns, I loop over the results. Keep in mind that I massage the route properties from their respective database names.
for (var i=0; i < $scope.routes.length; i++){ console.log( $scope.routes[i]) if ( $scope.routes[i].name.length == 0){ $ocLazyLoad.load([$scope.routes[i].controller]); } if ( $scope.routes[i].name.length > 0){ var _state = { name: $scope.routes[i].name, url: $scope.routes[i].url, templateUrl: $scope.routes[i].templateUrl, icon: $scope.routes[i].icon, displayName: $scope.routes[i].displayName, instructions: $scope.routes[i].instructions, c: $scope.routes[i].controller , lazyLoad : function($transition$,_controller){ return $transition$.injector().get('$ocLazyLoad').load(_controller.c); } } $stateRegistry.register(_state) if ($scope.routes[i].status == 'ROOT'){ $scope.goto($scope.routes[i].defaultRoute,JSON.parse($scope.routes[i].defaultParams)); } } }First I test to see if the .name (ROUTE_NAME) exists. If not, I assume that this is a file to be included into the application, but no route is needed. For example, this could be a dataService. If there is a .name, then I create an object called _state. For the ui-router, the key properties are the name, url, templateUrl and to lazyLoad the corresponding controller. For the lazyLoad function, I discovered (accidentally) that the second parameter passed in is the _state. This allows us to easily pass in the path to the controller file.
The next step, after the _state is defined, is to register the _state by using the $stateRegistery.register function. The final step is to navigate to the ROOT route. This is in lieu of setting the $urlProvider.otherwise property which I haven't figured out to do yet.
So that's it in a nutshell. Get a JSON list of the routes; iterate through building a state object for each route; and then registering each state.
Just as a note: You'll see additional properties defined in the _state that are not actually part of the ui-router. These properties are used later in the framework to help standardize the look and feel of the content.
Hope this wasn't too confusing. As time permits, I may add some clarity later.
Cheers!
Great article ...Thanks for your great information, the contents are quiet interesting.
ReplyDeleteAngular JS Training in Hyderabad
Angular JS Training in Ameerpet
Angular JS Training
Angular JS Online Training
thanks for your great information.
ReplyDeleteFull Stack Training in Chennai | Certification | Online Training Course | Full Stack Training in Bangalore | Certification | Online Training Course | Full Stack Training in Hyderabad | Certification | Online Training Course | Full Stack Training in Pune | Certification | Online Training Course | Full Stack Training | Certification | Full Stack Online Training Course