How to apply routing guards to feature module routing modules? - javascript

So, I'm building an Angular 4 app that I want all routes to be protected (except for the login route of course). I'm trying to use feature modules and feature module routing. So, imagine something like this:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { AuthGuardService } from './auth/auth-guard.service';
import { LoginComponent } from './login/login.component';
import { RegisterComponent } from './register/register.component';
import { ProtectedRouteComponent } from './protected-route/protected-route.component';
const routes: Routes = [
{ path: 'login', component: LoginComponent }, // no auth guard for login
{
path: '',
canActivate: [AuthGuardService],
children: [
{
path: '',
children: [
{ path: 'register', component: RegisterComponent },
{ path: 'protected', component: ProtectedRouteComponent }
]
}
]
}
];
#NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}
, for the root module, and then a users feature module routing config like:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { UsersComponent } from './users.component';
const routes: Routes = [
{ path: 'users', component: UsersComponent }
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class UsersRoutingModule {}
What would be the best way to:
Keep using feature module routing, and
Apply the route guards to the users feature module routing without replicating the canActivate guard? Is there any way I can pass it on to the users feature module routing from the root routing module?
Thanks,
Iraklis

Was looking for the same and the solution I found involves the following steps:
Do not import your feature module via app modules
Instead import the feature module as part of your app module routes
{
path: '',
canActivate: [AuthGuardService],
children: [
{
path: '',
children: [
{ path: 'register', component: RegisterComponent },
{ path: 'protected', component: ProtectedRouteComponent }
]
},
{
path: '',
children: () => UsersModule
}
]
}
One thing to consider:
Other modules will NOT have access to your UserModule's components and services (until you have visited one of the /users routes)
This might not be a problem as your modules might already be well separated

Related

Angular SSR app fail to render homepage from url while server is running

I have an Angular SSR app that is not able to render the homepage via localhost:4000 while the backend node server is running.
So if I go to localhost:4000 it will start loading but never display anything nor finished loading. However, if I go to another page like 404 where I have a button to take me to the home page it does load it. Additionally, if I turn off the backend server it does load the homepage.
The app routes are handled like this:
//app-routing.module.ts
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { GuardDashboardGuard } from './guard-dashboard.guard';
import { KYCGuard } from './guard-kyc.guard';
// More imports for other paths
const routes: Routes = [
{
path: 'profile-update',
canActivate: [GuardDashboardGuard, KYCGuard],
loadChildren: () =>
import('./pages/profile-update/profile-update.module').then((m) => m.ProfileUpdatePageModule),
},
// More paths with the same structure
{
path: '',
loadChildren: () => import('./pages/home/home.module').then((m) => m.HomePageModule),
},
{
path: 'faqs',
loadChildren: () => import('./pages/faq/faq.module').then((m) => m.FaqPageModule),
},
{
path: '',
redirectTo: '/',
pathMatch: 'full',
},
{ path: '**', redirectTo: '404' },
];
#NgModule({
imports: [
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled',
scrollOffset: [0, 0],
anchorScrolling: 'enabled',
relativeLinkResolution: 'legacy',
initialNavigation: 'enabledBlocking',
}),
],
exports: [RouterModule],
})
export class AppRoutingModule { }
I have tried fully deleting path: '', and the app redirected localhost:4000 to profile-update. Even if i delete profile-update I am still redirected to a Update Profile page.
Home page directory tree looks like:
.
├── home-routing.module.ts
├── home.module.ts
├── home.page.html
└── home.page.ts
// home-routing.module.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { HomePage } from './home.page';
const routes: Routes = [
{
path: '',
component: HomePage,
},
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class HomePageRoutingModule {}
I am not sure what the cause of this error is or what code is relevant so I don't know what other code should be included in my question.
I also get a network error of crbug/1173575, non-JS module files deprecated.
and have found this Crbug/1173575, non-JS module files deprecated. chromewebdata/(index)꞉5305:9:5551 which was not very helpful to solve thebug.

Angular maximum call stack error when lazy loading

There are some similar discussions, but the solutions did not work. I've attempted to recreate the module a couple of times now and Angular still throws the error Maximum call stack size exceeded. The admin component is brand new as well. All of these have been generated using CLI.
Here's my code:
App Routing
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { AuthGuard } from './guards/auth/auth.guard';
const routes: Routes = [
{
path: 'dashboard',
pathMatch: 'full',
data: { authorized: [true] },
canActivate: [AuthGuard],
loadChildren: () =>
import('./modules/feature/dashboard/dashboard.module').then(
(m) => m.DashboardModule
),
},
///// this admin import is the issue and I know this because if I comment it out then the app works
///// fine...
{
path: 'admin',
pathMatch: 'full',
data: { authorized: [true] },
canActivate: [AuthGuard],
loadChildren: () =>
import('./modules/feature/admin/admin.module').then((m) => m.AdminModule),
},
{
path: '',
pathMatch: 'full',
data: { authorized: [false] },
loadChildren: () =>
import('./modules/feature/website/website.module').then(
(m) => m.WebsiteModule
),
},
// {
// path: '*',
// component: MainComponent,
// data: { authorized: [false] },
// },
];
#NgModule({
imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' })],
exports: [RouterModule],
})
export class AppRoutingModule {}
Module
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { AdminRoutingModule } from 'src/app/routing/feature/admin-routing/admin-routing.module';
import { AdminComponent } from 'src/app/components/feature/admin/admin.component';
import { AdminService } from 'src/app/services/feature/admin.service';
#NgModule({
declarations: [AdminComponent],
imports: [CommonModule, AdminRoutingModule],
providers: [AdminService],
})
export class AdminModule {}
Admin Routing
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { AdminComponent } from 'src/app/components/feature/admin/admin.component';
const routes: Routes = [
{
path: '',
component: AdminComponent,
children: [],
},
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class AdminRoutingModule {}
Sometimes you bang your head against the wall because you've looked over your code a hundred times. Knowing good and well that it's not an error on your end. To find that the error can be solved via something simple. Like stopping the server, closing visual studio....re-opening visual studio and re-booting the server.
Which btw, solved my issue.

Trouble implementing lazy loaded feature module Angular 8

So basically I am trying to create a lazy loaded feature module in my application I have been following the official angular docs - but for some reason its not working.
I have set up my feature module DashboardModule as shown below
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
// MODULES
import { DashboardRoutingModule } from './dashboard-routing.module';
// COMPONENTS
import { DashboardComponent } from './dashboard/dashboard.component';
import { DashboardAlertComponent } from './dashboard-alert/dashboard-alert.component';
import { DashboardSummaryComponent } from './dashboard-summary/dashboard-summary.component';
import { DashboardTasksComponent } from './dashboard-tasks/dashboard-tasks.component';
import { HoldingPageComponent } from './holding-page/holding-page.component';
#NgModule({
imports: [CommonModule, DashboardRoutingModule],
declarations: [
DashboardComponent,
DashboardAlertComponent,
DashboardSummaryComponent,
DashboardTasksComponent,
HoldingPageComponent,
]
})
export class DashboardModule {}
then in my DashboardRoutingModule
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { ActivityComponent } from '../activity-components/activity/activity.component';
import { IsLockedRouteGuard } from '#app/shared/common/auth/is-locked-route-guard';
import { DashboardSummaryComponent } from './dashboard-summary/dashboard-summary.component';
import { SyncComponent } from '#app/popup-components/sync/sync.component';
import { DashboardAlertComponent } from './dashboard-alert/dashboard-alert.component';
import { ChartContainerComponent } from '../chart-components/chart-container/chart-container.component';
import { DashboardTasksComponent } from './dashboard-tasks/dashboard-tasks.component';
#NgModule({
imports: [
RouterModule.forChild([
{ path: 'activity', component: ActivityComponent, canActivate: [IsLockedRouteGuard] },
{ path: 'snapshot', component: DashboardSummaryComponent },
{ path: 'sync', component: SyncComponent },
{
path: 'alerts',
component: DashboardAlertComponent,
canActivate: [IsLockedRouteGuard]
},
{ path: 'charts', component: ChartContainerComponent, canActivate: [IsLockedRouteGuard] },
{ path: 'tasks/:sort', component: DashboardTasksComponent, canActivate: [IsLockedRouteGuard] },
])
],
exports: [RouterModule]
})
export class DashboardRoutingModule {}
so as per the angular docs this has been set up correctly..
now in my AppRoutingModule
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
import { AppRouteGuard } from './shared/common/auth/auth-route-guard';
#NgModule({
imports: [
RouterModule.forChild([
{
path: 'app',
component: AppComponent,
children: [
{
path: '',
children: [{ path: '', redirectTo: '/dashboard/alerts', pathMatch: 'full' }]
},
{
path: 'main',
canActivate: [AppRouteGuard],
loadChildren: () => import('./main/main.module').then(m => m.MainModule),
data: { preload: true }
},
{
path: 'dashboard',
loadChildren: () => import('./main/dashboard/dashboard.module').then(m => m.DashboardModule)
},
]
}
])
],
exports: [RouterModule]
})
export class AppRoutingModule {}
but whats happening is when I try and go to /dashboard.. I get this error
Component HoldingPageComponent is not part of any NgModule or the module has not been imported into your module.
but I am clearly importing it in the DashboardModule as shown above.. what am I doing wrong??
Thanks
i don't see
RouterModule.forRoot
i think you should use it in AppRoutingModule instead of
RouterModule.forChild

Angular 6 with 2 router outlet

how can I make sure to have at least 2 router-outlets and manage them at the routing level?
can link me a working jsfillde or stackblitz or similar?
edited re open problem
APP COMPONENT HTML
<main [#fadeInAnimation]="o.isActivated ? o.activatedRoute : ''">
<router-outlet #o="outlet" name="main"></router-outlet>
<router-outlet #o="outlet" name="second"></router-outlet>
</main>
APP MODULE
import { BrowserModule } from '#angular/platform-browser';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { HttpClientModule } from '#angular/common/http';
import { NgModule, APP_INITIALIZER } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
// components
import { AppComponent } from './app.component';
import { HomeComponent } from './components/home/home.component';
// models
import { Permissions } from '../app/models/permissions';
// guards
import { CanAccess } from '../app/guards/canaccess';
import { OtherComponent } from './components/other/other.component';
import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
const permissions: Permissions = new Permissions();
const appRoute: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent, data: { permission: permissions }, canActivate: [CanAccess], outlet: 'main' },
{ path: 'other', component: OtherComponent, data: { permission: permissions }, canActivate: [CanAccess], outlet: 'second' },
{ path: 'pageNotFound', component: PageNotFoundComponent, data: { permission: permissions }, canActivate: [CanAccess], outlet: 'main' },
{ path: '**', redirectTo: 'pageNotFound', pathMatch: 'full' },
];
export function appConfigFactory() {
try {
return () => true;
} catch (e) {
console.log(`catch load: ${e}`);
}
}
#NgModule({
declarations: [
AppComponent,
HomeComponent,
OtherComponent,
PageNotFoundComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
RouterModule.forRoot(appRoute)
],
providers: [
CanAccess,
{
provide: APP_INITIALIZER,
useFactory: appConfigFactory,
deps: [],
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
ERROR
ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'home'
Error: Cannot match any routes. URL Segment: 'home'
can view on editor
https://stackblitz.com/edit/angular-ghusfs
thanks
You may define parent child component to use multiple router-outlets like this.
{
path: 'shop', component: ParentShopComponent,
children : [{
path: 'hello', component: ChildShopComponent
}]
}
Your first <router-outlet> will be in app component & second in ParentShopComponent rest of components can lend in child level or parent.
But if your relationship is child parent than check this out Named Router Outlets
Example
This is main Router OUtlet
These are named ones
<div class="columns">
<md-card>
<router-outlet name="list"></router-outlet>
</md-card>
<md-card>
<router-outlet name="bio"></router-outlet>
</md-card>
</div>
And here's how you use them
{ path: 'speakersList', component: SpeakersListComponent, outlet: 'list' }

Angular2 nested module routing with same routes

I'm facing a common problem in a backend app.
I got several ressources which can be viewed by consulting this kind of routes:
reports/view/:id
campains/view/:id
suts/view/:id
certifications/view/:id
Note that the route ends with the same part : /view/:id.
My app modules are :
App.module
|-MainLayoutModule
|- ReportModule
|- CampaignModule
|- SutModule
|- ...
Each module (except mainlayoutModule) defines it's own routing.
App.routing
{
path:'certification',
loadChildren: './+certification/certification.module#CertificationModule',
canActivate:[AuthGuard]
},
{
path:'reports',
loadChildren: './+report/report.module#ReportModule'
canActivate:[AuthGuard],
},
{
path:'suts',
loadChildren: './+sut/sut.module#SutModule',
canActivate:[AuthGuard]
},
{
path:'campaigns',
loadChildren: './+campaign/campaign.module#CampaignModule',
canActivate:[AuthGuard]
},...
Report.routing
import { Routes, RouterModule } from '#angular/router';
import { ReportDetailsComponent } from "./ReportDetails/report-details.component";
import { ReportDetailsResolver } from "./ReportDetails/report-details.resolver";
import { ReportListComponent } from "./ReportsList/report-list.component";
export const reportRoutes: Routes = [
{
path: '',
pathMatch: 'full',
redirectTo: 'list'
},
{
path: 'view/:id',
component: ReportDetailsComponent,
data: {
pageTitle: 'Report detail'
},
resolve: {
report: ReportDetailsResolver
},
pathMatch: 'full'
},
{
path: 'list',
component: ReportListComponent,
data: {
pageTitle: 'Reports Lists'
},
pathMatch: 'full'
}
];
export const reportRouting = RouterModule.forChild(reportRoutes);
Campaign.routing
import { Routes, RouterModule } from '#angular/router';
import { CampaignDetailsComponent } from './campaignDetails/campaign-details.component'
import { CampaignDetailsResolver } from './campaignDetails/campaign-details.resolver'
import { CampaignListsComponent } from './campaignList/campaign-list.component'
export const campaignRoutes: Routes = [
{
path: 'view/:id',
component: CampaignDetailsComponent,
data: {
pageTitle: 'Campaign detail'
},
resolve: {
campaign: CampaignDetailsResolver
},
pathMatch: 'full'
},
{
path: 'lists',
component: CampaignListsComponent,
pathMatch: 'full'
}
];
export const campaignRouting = RouterModule.forChild(campaignRoutes);
The campaign module needs to use directive from the report Component, here is it's code :
#NgModule({
imports: [
CommonModule,
campaignRouting,
ReportModule
],
declarations: [CampaignDetailsComponent,CampaignListsComponent],
providers:[CampaignDetailsResolver]
})
export default class CampaignModule { }
Here is the problem : when i go to the route "/campaigns/view/:id" the router outlets loads content from the report component module and not from the campaign component...
A stupid solution would be to have unique route in each module (like /view Report/:id, /viewCampaign/:id... ) but i think i'm missing something in my app routing configuration....
Any idea on how to solve this kind of problem?
Thanks,
Olivier
I think the best solution here could be to change the way that you create your app hierarchy.
By using a "root" component for each module (report, campaign and stut), you could define "children" routes.
Here is an example from the "Routing and Navigation" Guide :
const crisisCenterRoutes: Routes = [
{
path: 'crisis-center',
component: CrisisCenterComponent,
children: [
{
path: '',
component: CrisisListComponent,
children: [
{
path: ':id',
component: CrisisDetailComponent
},
{
path: '',
component: CrisisCenterHomeComponent
}
]
}
]
}
];
#NgModule({
imports: [
RouterModule.forChild(crisisCenterRoutes)
],
exports: [
RouterModule
]
})
export class CrisisCenterRoutingModule { }
Also, i would recommend to follow a "Routing Module" way, like the one presented on the same guide :
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { HeroListComponent } from './hero-list.component';
import { HeroDetailComponent } from './hero-detail.component';
const heroesRoutes: Routes = [
{ path: 'heroes', component: HeroListComponent },
{ path: 'hero/:id', component: HeroDetailComponent }
];
#NgModule({
imports: [
RouterModule.forChild(heroesRoutes)
],
exports: [
RouterModule
]
})
export class HeroRoutingModule { }

Categories