Angular 404 page routing for nested modules - javascript

I'm Using nested modules in my project
.
└─ AppModule
├─ MallModule
├─ OtherModule
└─ ...
In the main route I only configured top-level routes:
app-routing.module.ts
const routes: Routes = [
{ path: '', redirectTo: '/', pathMatch: 'full' },
{ path: 'login', component: LoginComponent},
{ path: 'register', component: RegisterComponent },
{ path: '404', component: NotfoundComponent },
{ path: '**', redirectTo: '404' }, // Added
]
Separately, I configured routes separately in each sub-modules, like:
mall-routing.module.ts
const routes: Routes = [
{
path: '',
component: MallComponent,
children: [
{
path: '',
component: HomeComponent,
},
{
path: 'about',
component: AboutComponent,
},
...
}
]
The result is, because that no other routes are defined in the main routing configs, all requests other than login/register/404 will be redirected to 404.
Is there anyway I can use a correct 404 redirection but keep the current route file structure? I don't hope to gather all route configs together.
Thanks!

import the 'Other' modules in your app modules, this will allow the routes defined in those modules to be used.
The updated code should look something like this:
imports: [
MallModule,
OtherModule
RouterModule.forRoot([ // Add the configuration here, which is not a part of other module ])
]

in routing load your modules like below
// MallModule
{
path: "path",
canLoad: [AuthGuard],
loadChildren: "./modules/MallModule.module#MallModule",
},

I arrived in at this question after one module worked fine with the routing but another gave 404 for all its subpages.
The problem for me was the order in app.modules.ts. I had the submodules after the import of AppRoutingModule in the list of imports. Once I moved that last, than the routing of submodules and 404 page worked fine.
In app.module.ts.
imports: [
BrowserModule,
HttpClientModule,
FormsModule,
SubModule,
AuthorizationModule,
CommonModule,
FontAwesomeModule,
ProfileModule, // this was previously defined after AppRoutinModule
AppRoutingModule // this must be last in list for routing with 404 to work
]
and in app-routing.modules.ts.
const routes: Routes = [
// https://angular.io/guide/router
{ path: 'help', component: HelpComponent },
{ path: 'terms', component: TermsComponent },
{ path: 'contact', component: ContactComponent},
{ path: '404', component: PageNotFoundComponent},
{ path: '**', component: PageNotFoundComponent}
];

Related

Is there a way I can render a 2 level nested component in Angular using `router-outlet`?

I have a sidebar with some links. The sidebar is located at the /dashboard route. The links on the sidebar are direct children to /dashboard. I now want to render the children of /dashboard inside the main router-outlet. I have no idea on how to approach this.
The following are some code snippets to elaborate my question further
My routing structure
const routes: Routes = [
{
path: '',
component: LoginComponent,
},
{
path: 'dashboard',
component: DashboardComponent,
children: [
{
path: 'roles',
component: RolesComponent,
},
{
path: 'workgroups',
component: WorkgroupsComponent,
children: [
{
path: 'savewg',
component: WgDetailsComponent,
},
]
},
{
path: 'users',
component: UsersComponent,
},
],
},
];
App component
<!-- Main app component -->
<div class="app-view">
<router-outlet></router-outlet>
</div>
Login.html
<button mat-raised-button color="warn" class="login-field" (click)="login(email, password)"
<!-- rest of code ommited for brevity -->
Login.ts
public login(email: string, password: string) {
this.router.navigate(['dashboard'], { replaceUrl: true });
}
Workgroup Component html
<button mat-raised-button color="warn" [routerLink]="['savewg']">
<mat-icon>add</mat-icon>
New
</button>
<!-- Code ommited for brevity -->
<router-outlet></router-outlet>
<div class="workgroup-filters">
<mat-form-field appearance="outline">
<!-- rest of Code ommited for brevity -->
When I click on the new button in the workgroup component, I want it to navigate me to the savewg component view and replace the content in the workgroup component.
Any suggestions on how I can tackle this will be appreciated
Modules are only allow one main router-outlet per module. You will have to create a separate module for workgroups path and lazy load it. The workgroups module will have its own routing file and its own router outlet where you will load all your routes from your workgroup module. See below stackblitz for a working example.
app-routing.module.ts
const routes: Routes = [
...
{
path: 'workgroups',
loadChildren: () => import('./workgroups/workgroups.module').then(m => m.WorkgroupsModule)
},
...
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
workgroups-routing.module.ts
const routes: Routes = [
{
path: '',
component: WorkgroupsComponent,
children: [
{
path: 'savewg',
component: WgDetailsComponent
},
{
path: '**',
redirectTo: 'savewg',
pathMatch: 'full'
}
]
},
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class WorkgroupsRoutingModule { }
workgroups.module.ts
#NgModule({
imports: [
CommonModule,
WorkgroupsRoutingModule
],
declarations: [
WorkgroupsComponent,
WgDetailsComponent
]
})
export class WorkgroupsModule { }
Below are resources for lazy loading modules and a stackblitz example.
https://stackblitz.com/edit/angular-ivy-hbogtn
https://www.freakyjolly.com/angular-nested-routing-with-multiple-routeroutlet-using-loadchildren-having-own-router-modules-example-application/#.X3IQa3WYXmE
I found a better solution to this. It turns out that Angular will load the empty path route as the default route and there is no need to worry about router outlet anymore. I modified my app-routing.module.ts in the following way:
const routes: Routes = [
{
path: '',
component: LoginComponent,
},
{
path: 'dashboard',
component: DashboardComponent,
children: [
{
path: 'roles',
component: RolesComponent,
},
{
path: 'workgroups',
children: [
{
path: 'savewg',
component: WgDetailsComponent,
},
{
path: '',
component: WorkgroupsComponent,
},
],
},
{
path: 'users',
component: UsersComponent,
},
],
},
];
As you can see, I've added an empty path as a child in the
workgroups component This may not be perfect, more approaches and
solutions are welcome.

Split routes into separate modules in angular 6

I'm working on an Angular 6 application. Currently I'm struggling with routing. I'm interested, whether mine structure, what I have imagined can work or not. So it looks like this:
App module - contains main routing with some parent route, where layout is defined. Like this:
const routes: Routes = [
{
path: 'login',
component: LoginComponent
},
{
path: '',
component: LayoutComponent,
canActivate: [AuthGuard],
canActivateChild: [AuthGuard],
children: [
// {
// path: 'brands',
// loadChildren: 'app/modules/brands/brands.module#BrandsModule',
// pathMatch: 'prefix'
// }
]
}
];
#NgModule({
imports: [RouterModule.forRoot(routes), BrandsModule, ItemsModule],
exports: [RouterModule],
providers: [BosRouteLoader]
})
export class RoutingModule {}
One of mine feature module defines its own routing in a module like this:
const routes: Routes = [
{
path: 'brands',
children: [
{ path: '', component: BrandListComponent },
{ path: ':id', component: BrandDetailComponent },
{ path: '**', redirectTo: '' }
]
}];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class BrandsRoutingModule {}
I would like to achieve that every feature module will define its own routing and those routes are registered as a child routes of the App module.
With lazy loading I can manage it but then I have to define one more route always in mine App module, however I just want to define it in feature module.
If I do it without lazy loading, then mine parent route in App component is never hit. So if I go to http://localhost/brands it will load the appropriate BrandLisComponent but without LayoutComponent.
Is ther a way to define routes in feature module and register them as a child of main main routing module?
The concept is that you define a module routing in your higher-level module and then define its children in your desired module.
So in your case, you need to tell the angular that, hey when someone goes to brands route, use BrandsRoutingModule routings.
So in your app module, you're going to have:
{
path: 'brands',
loadChildren: 'app/modules/brands/brands.module#BrandsModule',
canActivate: [AuthGuard],
canActivateChild: [AuthGuard],
}
This tells that you need to load the routing of that module if the user goes to /brand.
Then in your BrandsRoutingModule, you need to define routes to be:
{
path: '',
component: LayoutComponent,
children: [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: BrandListComponent },
{ path: ':id', component: BrandDetailComponent },
{ path: '**', redirectTo: '' }
]
}
So whenever we route to /brands, we shall see the LayoutComponent as a main route relative to that and then the BrandListComponent and others will come as his children. But to show his children, you also need to put this line of code in your layout.component.html:
<router-outlet></router-outlet>
this tells angular that, hey if he's going to for example /brands/2, you need to load the BrandDetailComponent inside the LayoutComponent, literally as his child.
Hope it helps.
Imans77's answer works for lazy loaded modules (although the string from of LoadChildren is now deprecated). However, with eager loaded modules, if you want to tidy up the main routes module and split the file accross different modules, you could try the following approach:
app-routing.module.ts
const MODULE_ROUTES = [...module1Routes, module2Routes];
const routes: Routes = [
{ path: 'path1', component: Path1Component },
{ path: 'path2', component: Path2Component },
...MODULE_ROUTES,
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Instead of declaring all children of every component/module in the main routing file, you could create a *.route.ts file for each feature module, in which you could just declare and export routes in a normal way. For example:
export const module1Routes: Routes = [
{
path: 'brands',
children: [
{ path: '', component: BrandListComponent },
{ path: ':id', component: BrandDetailComponent },
{ path: '**', redirectTo: '' }
]
}];
By importing it in the main routing file, they would immediately be available for Angular.

Angular 5: I can navigate to a module's route without including the module's path segment in the URL?

So I built an Angular 5.2.0 app that I divided into 3 modules:
An admin module, to be loaded when the user navigates to any admin/** route,
A prefect module, to be loaded when the user navigates to any prefect/** route,
An authentication module, to be loaded in every other case.
Each module does its own routing. For instance /admin/student/list
activates the StudentListComponent defined within the admin module.
Now if I go to /student/list, without the /admin part, it will load that same StudentListComponent! And this can be reproduced with every route defined in the app's modules.
This is obviously not desirable behavior. Especially given that I have route guards in place to protect the admin and prefect modules and this makes it very easy to circumvent them.
Any insights appreciated. Is it a bug? Or am I doing something wrong?
This is the code I have in app.module.ts:
export const routes: Routes = [
{
path: 'admin',
loadChildren: 'app/modules/admin/admin.module#AdminModule',
canActivate: [AdminGuard]
},
{
path: 'prefect',
loadChildren: 'app/modules/prefect/prefect.module#PrefectModule',
canActivate: [PrefectGuard]
},
{
path: '',
loadChildren:
'app/modules/authentication/authentication.module#AuthenticationModule'
},
{
path: '**',
redirectTo: '/login'
}
];
#NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
BrowserAnimationsModule,
RouterModule.forRoot(routes),
AuthenticationModule,
PrefectModule,
AdminModule
],
providers: [AdminGuard, PrefectGuard],
bootstrap: [AppComponent]
})
export class AppModule {}
And in admin.module.ts:
const routes: Routes = [
{
path: '',
component: AdminComponent,
children: [
{
path: 'student',
children: [
{
path: 'list',
component: StudentListComponent
},
{
path: 'new',
component: StudentEditComponent
},
{
path: ':id',
component: StudentItemComponent
},
{
path: ':id/edit',
component: StudentEditComponent
}
]
}
]
}
];
#NgModule({
imports: [
CommonModule,
RouterModule.forChild(routes),
HttpClientModule,
FormsModule,
// Angular Material modules...
NavigationModule
],
providers: [StudentService],
declarations: [
AdminComponent,
StudentListComponent,
StudentItemComponent,
StudentEditComponent
]
})
export class AdminModule {}
And in authentication.module.ts:
const routes: Routes = [
{
path: '',
component: AuthenticationComponent,
children: [
{
path: 'login',
component: LoginComponent
},
{
path: 'reset',
component: ResetPasswordComponent
},
{
path: '',
redirectTo: '/login',
pathMatch: 'full'
}
]
}
];
#NgModule({
imports: [
CommonModule,
RouterModule.forChild(routes),
FormsModule,
// Angular Material modules...
],
providers: [AuthenticationService, AdminService, StudentService],
declarations: [
AuthenticationComponent,
LoginComponent,
ResetPasswordComponent
]
})
export class AuthenticationModule {}
You're importing your lazy-loaded AdminModule inside your app component here :
imports: [
BrowserModule,
BrowserAnimationsModule,
RouterModule.forRoot(routes),
AuthenticationModule,
PrefectModule,
AdminModule
],
so it is actually not lazy-loaded but loaded when AppModule is. So the routes of AdminModule will be accessible both from '/admin' since and the root : '/'.
Just remove it from the imports of you AppModule and it should be fine.
I created a small repo with a working example of what you're trying to achieve here
Hope that helps
Ok, I found the solution: in app.module.ts, I'm importing the feature modules (AdminModule, etc.) and that somehow produces that effect.
I removed these imports, and problem solved.

Angular Routes not mapping properly for lazy loading

So I have an app with multiple modules that has routes properly put in place, and each module has it's own routes. Everything works fine, until I try to implement lazy loading.
Previous State:
example module
export const EXAMPLE_ROUTES: Routes = [
{ path: 'new', component: AddOpportunityComponent },
{ path: ':id', component: OpportunityProfileComponent,
children: [
{
path: 'edit/sdg-info', component: SdgInfoComponent
}
]}
];
I import this EXAMPLE_ROUTES in example module
Now I have root level routing as
const APP_ROUTES: Routes = [
{ path: '', component: HomeComponent},
{ path: 'search', component: SearchComponent },
{ path: 'example', component: ExampleComponent, children: [...EXAMPLE_ROUTES], canActivate: [AuthGuard, OnboardedGuard] },
];
export const appRouting = RouterModule.forRoot(APP_ROUTES, {enableTracing: true});
With this setup it works fine
After trying to have lazy loading
example module
const EXAMPLE_ROUTES: Routes = [
{ path: 'new', component: AddOpportunityComponent },
{ path: ':id', component: OpportunityProfileComponent,
children: [
{
path: 'edit/sdg-info', component: SdgInfoComponent
}
]}
];
export const exampleRouting = RouterModule.forChild(EXAMPLE_ROUTES);
and app routing becomes
const APP_ROUTES: Routes = [
{ path: '', component: HomeComponent},
{ path: 'search', component: SearchComponent },
{ path: 'example', loadChildren: './example/example.module#ExampleModule', canActivate: [AuthGuard, OnboardedGuard] }
];
export const appRouting = RouterModule.forRoot(APP_ROUTES, {enableTracing: true});
The problem I'm facing is, the example route works fine, now the /search route breaks, as the router for some reason tries to match it with opportunity route (path: ':id')
What might be going wrong here?
This issue can occoure when you first implement your FeatureModule in your RootModule and after a given time you decide you want to load this FeatureModule lazy via loadChildren and you forgot to remove FeatureModule from your imports in your RootModule.
In your case your Routing Configuration will look something like this after compilation (PSEUDO-CODE):
const Routes_CONFIG = [
{ path: '', component: HomeComponent},
{ path: 'search', component: SearchComponent },
{ path: 'example', loadChildren: './example/example.module#ExampleModule', canActivate: [AuthGuard, OnboardedGuard] }
{ path: 'new', component: AddOpportunityComponent },
{ path: ':id', component: OpportunityProfileComponent,
children: [
{ path: 'edit/sdg-info', component: SdgInfoComponent }
]
}
]
In your case, when you just enter /search you will match :id OpportunityProfileComponent. That's because the router accepts the first route that matches a navigation request path.

Lazy loaded module base template

In app.module.ts I load 2 lazy modules like this
const appRoutes: Routes = [
{ path: 'anonym', loadChildren: './anonym/anonym.module#AnonymModule' },
{ path: 'user', loadChildren: './user/user.module#UserModule', canActivate: [AuthGuard] }
];
In app.component.html I can write some base html. My question - is there any way to have base html for my UserModule?
I have tried to create user.component.ts and load it like in app.module.ts
import { UserComponent } from './user.component';
#NgModule({
declarations: [UserComponent],
bootstrap: [UserComponent]
});
but it's not show me user.component.html
In your user module define a base route with an empty path, and then define the sub-paths as children.
const ROUTES: Routes = [
{
path: '',
component: UsersComponent,
children: [
{
path: '',
pathMatch: 'full',
redirectTo: 'login'
}, {
path: 'login',
component: LoginComponent
}, {
path: 'logout',
component: LogoutComponent
}
]
}
];
The UsersComponent will now be used as a base component, and if you navigate to just /users it will redirect to the /users/login path.
Make sure your UsersComponent has a template with <router-outlet></router-outlet> so the child routes.
#NgModule({
imports: [
RouterModule.forChild(ROUTES)
],
exports: [
RouterModule
]
})
export class UsersModule {
}

Categories

Resources