I'm currently working on a project where I am in the process of converting an AngularJS application to Angular. The main challenge that I am facing at the moment revolves around routing.
To sum it up: My requirement is to define routes based on an API response prior to utilizing the routing module.
In the functioning scenario with AngularJS: (More or less pseudo code provided below)
There are some basic routes that are universally available, these are set in the standard AngularJS manner:
/home
/settings
...and so on
Additionally, there are dynamic routes generated depending on the API response
/purchase-requests
/invoices
/godzilla
...and more. The actual content isn't significant, essentially, it's a dynamic list of routes obtained from an existing API in the form of an array of strings
The fundamental procedure followed by the existing AngularJS app:
- The AngularJS app is NOT immediately associated with an element using ng-app as commonly done.
- A pure (or jQuery) response is fetched from the API upon page loading.
- The initialization of the AngularJS app occurs through:
angular.bootstrap(document.getElementById('mainElementId'),['appName']);
This method functions due to AngularJS's behavior of delaying the .config() execution until the Angular app is bootstrapped, which we defer until after receiving the API response.
Here is an example of functional AngularJS code used today:
<script>
let appList = [];
const mainApp = angular.module('mainApp', ['ngRoute']);
// Controllers
mainApp.controller('mainController', mainController);
mainApp.controller('homeController', homeController);
mainApp.controller('appListController', appListController);
mainApp.controller('appSingleController', appSingleController);
mainApp.controller('errorController', errorController);
// config will not be called until the app is bootstrapped
mainApp.config(function($routeProvider) {
// Default routes for all users
$routeProvider.when('/', { templateUrl: 'views/home.html', controller: 'homeController'});
$routeProvider.when('/home', { templateUrl: 'views/home.html', controller: 'homeController'});
// Incorporate the dynamic routes received from the API
for (let appName in appList) {
$routeProvider.when(`/${appName}`, { templateUrl: 'views/app-list.html', controller: 'appListController'});
$routeProvider.when(`/${appName}/new`, { templateUrl: 'views/app-single.html', controller: 'appSingleController'});
$routeProvider.when(`/${appName}/view/:itemNumber`, { templateUrl: 'views/app-single.html', controller: 'appSingleController'});
}
$routeProvider.otherwise({ templateUrl: 'views/error.html', controller: 'errorController'});
});
$(document).ready(function() {
const options = {
type: 'GET',
url: '/api/apps/getAvailableApps',
success: onAppSuccess,
};
$.ajax(options);
});
function onAppSuccess(response) {
appList = response.appList;
angular.bootstrap(document.getElementById('mainApp'), ['mainApp']);
}
</script>
<!-- Typically, you bind to the app using ng-app="mainApp" -->
<div id="mainApp" class="hidden" ng-controller="mainController">
<!-- Route views -->
<div ng-view></div>
</div>
In Angular 9 (or seemingly any recent version of Angular), routes are defined within the routing module before initializing the main component:
const routes: Routes = [
{ path: 'login', component: LoginComponent },
{ path: '', component: DashboardComponent },
{ path: 'home', component: DashboardComponent },
{ path: 'settings', component: SettingsComponent },
];
Using router.resetConfig
doesn't provide a solution
If I have the main module load the API configuration first and then employ resetConfig
based on the response, everything works fine if the user initially navigates to /
, /home
, or one of the other predetermined routes: The new dynamic routes are formed and navigation to them proceeds smoothly.
However, if a user directly navigates to a route that isn't predefined (for instance, /godzilla), the router prevents the page from loading altogether (or) if the wildcard route is set, presents the 404 error. The ngOnInit() function in the main component (which I intended to use to fetch the API response) never gets executed.
The question remains: How can I establish routes based on the API response before executing or even initializing the router navigation?