Reputation: 760
I'm working on an Angular app where we want to have the routes defined as Enums. Then, for the enums declare the specific routes that they point to. The Enums are bound to string values that match keys in CMS-system.
For instance, our first naive implementation was:
mainRoutes.ts
export enum RouteKey {
Dashboard = "dashboard",
Summary = summary"
}
export routes = {
[RouteKey.Dashboard]: "dashboard",
[RouteKey.Summary]: "summary"
}
In app.routing.module.ts
, these two variables are then imported and used like this:
...
{
path: routes[RouteKey.Dashboard],
component: DashboardComponent,
},
{
path: routes[RouteKey.Summary],
component: SummaryComponent,
}
This code runs fine when running in development, however with ahead-of-time compilation it fails during compilation, with the message expression form not supported
visible in the terminal, pointing to the first line that uses the computed entry ([RouteKey.Dashboard]: "dashboard"
).
Fair enough. We then attempted another approach using Javascript Map objects, like so:
...
export const routes = new Map();
routes.set(RouteKey.Dashboard, "dashboard");
routes.set(RouteKey.Summary, "summary");
With the references in app.routing.module.ts
updated to routes.get(***)
instead of routes[***]
.
and again the code runs fine when running development mode, and this time the code builds correctly.
However, when hosting the build and visiting the site, I get the following error in the browser:
Invalid configuration of route '': routes must have either a path or a matcher specified
Does anyone know how I can solve this issue? Is it at all possible to have a computed dictionary object for holding routes in an Angular application that uses Ahead of Time-compilation?
Upvotes: 2
Views: 323
Reputation: 3511
Forgive me if I had misinterpreted or misread your question... But based on your comment for the answer
The problem is I have a set of current and a set of deprecated routes that have different route values, but should use the same enums.
So you have 2 sets of routes and the only difference between them are the route values.
i.e. (Right-hand-side) "dashboard", "summary", etc are different but the object property names (left-hand-side) that identifies these route values remain the same.
Therefore, I should think there isn't a need for you to use ENUM or computed properties at all. I think you can simply use an interface to define current routes. Then, reuse the same interface for your deprecated routes.
mainRoutes.ts
export const myAppRoutes: IRoutes = {
dashboard: "dashboard",
summary: "summary",
home: "home",
login: "login",
settings: "settings"
}
export const myDeprecatedRoutes: IRoutes = {
dashboard: "olddashboard",
summary: "oldsummary",
home: "oldhome",
login: "oldlogin",
settings: "oldsettings"
}
export interface IRoutes{
dashboard: string;
summary: string;
home: string;
login: string;
settings: string;
}
app-routing-module.ts
//Need not necessary be environment.production, you can use other conditions
var myRoutes: IRoutes = environment.production ? myAppRoutes : myDeprecatedRoutes;
const routes: Routes = [
{
path: myRoutes.dashboard,
component: DashboardComponent,
},
{
path: myRoutes.summary,
component: SummaryComponent,
},
{
path: myRoutes.settings,
component: SettingsComponent
}
// Paths for LoginComponent, etc
];
Then, in your components, you can use back the same route names you had defined in mainRoutes.ts by importing them again, this will allow your app to work even when different routes are loaded. e.g.:
app.component.html
<a class="card" [routerLink]="'/' + loadedRoutesNames.dashboard">
<a class="card" [routerLink]="'/' + loadedRoutesNames.summary">
<a class="card" [routerLink]="'/' + loadedRoutesNames.settings">
app.component.ts
export class AppComponent{
loadedRoutesNames: IRoutes = environment.production ? myAppRoutes : myDeprecatedRoutes;
}
Here's a Stackblitz Example 🚀🚀 which I had ported over from a local project, I was able to run in production mode with Angular 8.
Upvotes: 1
Reputation: 6821
Instead of your export of routes
, I would suggest instead to use directly your enum constant;
export enum RouteConstants {
Dashboard = 'dashboard',
Summary = 'summary',
...
}
And you can use it in your route:
{
path: `:${RouteConstants.Dashboard}`,
...
}
Upvotes: 3