I'm loading a books module with the following routing configuration (src/app/index.ts) -- Note that this is a stackblitz link - And it now works by implementing the fix in the answer - to break it remove the authguard from the Books Module routing:
{
path: 'books',
loadChildren: './books/books.module#BooksModule',
canActivate: [AuthGuard],
},
The routing in the books module (src/app/books/index.ts) looks like this:
export const routes: Routes = [
{ path: '', component: CollectionPageComponent },
];
For some reason loading this route switches off the AuthGuard / the CanActivate guard does not trigger. There is a logging statement inside it tracking when it triggers.
If the route is commented out like this:
export const routes: Routes = [
//{ path: '', component: CollectionPageComponent },
];
Then the guard triggers. Thoughts?
The problem is that the authguard needs to live inside your BooksModule route definition.
#in books/index.ts
export const routes: Routes = [
{ path: '', component: CollectionPageComponent, canActivate: [AuthGuard] },
];
you can then remove the canActivate from app/index.ts
You can only use the canActivate guard with component. If you want guard on your lazy-loaded module, use canLoad guard.
Related
I'm having problems developing a route as default... if you put sitename.com ... it assumes the default Login route, getting sitename.com/login, so far so good....
My problem is that if I go to the page through a sitename.com/home shortcut... I don't see any page, as if I couldn't find the path... I wanted to put this shortcut on the default page. .. Login.
To do this do I have to configure the routes or do I have to do something else?
Can anyone help me?
app.module.ts
import { RouterModule, Routes } from '#angular/router';
imports: [
RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' }),
],
const routes: Routes = [
{ path: '', redirectTo: 'login', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
];
You can try
RouterModule.forRoot(routes, {useHash: true})
and Login page will be accessed by direct URL as sitename.com/#/login
My application contains two different layouts. One layout is the application where we show the top navigation and a sidebar.
<app-nav></app-nav>
<div>
<app-sidebar></app-sidebar>
<router-outlet></router-outlet>
</div>
and the second layout is the login and signup pages where we don't have the navigation bar and sidebar.
The naive solution will be to add ngIf to both elements based on the current route. But I prefer avoiding it. The reason is that we have code inside these components that we don't want to load where we don't need to.
Is there any better solution to this issue?
Have the AppComponent contain an router-outlet as the template.
#Component({
selector: 'app-root',
template: `<router-outlet></router-outlet>`
})
export class AppComponent {
constructor() {
}
}
Then include routes as:
const routes: Routes = [
{
path: '',
pathMatch: 'full',
component: AppComponent,
canActivate: [LanguageGuard]
},
{
path: ':lang',
component: LanguageComponent,
children: [
{
path: 'partner',
loadChildren: () => import('./partner/partner.module').then(m => m.PartnerModule)
},
...ClientRoutes,
...AuthRoutes
]
}
];
My project have different layouts for the partner and ClientRoutes/AuthRoutes
Partner:
const routes: Routes = [{
path: '',
component: PartnerLayoutComponent,
children: [
{
path: '',
component: HomeComponent
},
{
path: 'profile',
component: ProfileComponent
}
]
}];
This is the content of ClientRoutes/AuthRoutes:
export const ClientRoutes: Routes = [{
path: '',
component: ClientLayoutComponent,
children: [
{
path: '',
component: HomeComponent
},
{
path: 'sofa',
component: SofaComponent
}
]
}];
Then you change my PartnerModule as your login module and lazy load it.
But don't every user need to login? Maybe only put the signup process in that module.
If you're lazy-loading your modules, it's easy:
Add a second "layout" page with a <router-outlet>
In your routes, define your route like this:
const routes:Routes=[{path:'some-path', component: YourLayoutComponent, loadChildren: ()=> import('./lazy-loaded-module/lazy-loaded.module').then(m=>m.LazyLoadedModule) }];
I have a base route with three sibling routes. The parent route routes to my task-list.component.ts which contains a navbar and router outlet.
I would like to have a route param on the base route where I can add an optional token
so when I navigate to http://localhost:4200 token should be undefined.
when I navigate to http://localhost:4200/123 token should be 123 in the activated route params
I have the below route config but i'm encountering confusing/strange behaviour.
When I navigate to http://localhost:4200 I get to my base taskList.component as expected.
When I try navigate to http://localhost:4200/123 I get a 404 not found? The expected bahaviour is that this should have navigated to taskList.component and added 123 to the activated route params...
even more strange when I click the deleted link in my navbar it navigates to the parent component app.component again only then I get "deleted" as the value in the activated route params...
Even more strange: when I navigate to http://localhost:4200 using my browser it doesn't set deleted as token instead I get a 404 not found again...
Any idea how I can achieve the above/what my issue might be?
my route module code:
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
import { TaskListComponent } from './task/task-list/task-list.component';
import { CompletedTasksComponent } from './task/completed-tasks/completed-tasks.component';
import { DeletedTasksComponent } from './task/deleted-tasks/deleted-tasks.component';
const routes: Routes = [
{ path: '', component: TaskListComponent, pathMatch: 'full' },
{ path: 'completed', component: CompletedTasksComponent },
{ path: 'deleted', component: DeletedTasksComponent },
{ path: ':token', component: TaskListComponent },
{ path: ':token/completed', component: CompletedTasksComponent },
{ path: ':token/deleted', component: DeletedTasksComponent }
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
app.component.html:
<nav mat-tab-nav-bar>
<a mat-tab-link
*ngFor="let link of links"
[routerLink]="navigate(link)"
(click)="activeLink = link"
[active]="activeLink == link">{{link}}</a>
</nav>
<router-outlet></router-outlet>
app.component.ts navigate method
navigate(link) {
switch(link) {
case 'Task List':
return `${this.token}`;
case 'Completed Tasks':
return `${this.token}/completed`;
case 'Deleted Tasks':
return `${this.token}/deleted`;
}
}
Old answer: You have some issues in your routes. you can fix it like :
RouterModule.forRoot([
{ path: "", component: TaskListComponent, pathMatch: "full" },
{ path: "deleted", component: DeletedTasksComponent },
{ path: ":id", component: TaskListComponent },
{ path: ":id/completed", component: CompletedTasksComponent },
{ path: ":id/deleted", component: DeletedTasksComponent }
])
Run It On Stackblitz
Update :
based on your edit and comments, now in app navigation works but you get 404 when you refresh the page (even in development environment). so try this: https://stackoverflow.com/a/35285068/4718434 . (Also on production, you should configure your server to return angular html file on every path.)
I have a home route which is used by both an admin and a user, is there a way where I can show UserComponent if you are logged in as a user, and show AdminComponent if you are logged in as an admin?
This is what I currently have:
const routes: Routes = [
{ path: 'login', component: LoginComponent },
{
path: 'home',
component: HomeComponent,
children: [
// Children routes mix of user/admin paths
]
}
]
What I was thinking is that maybe I could do something like this, however, I don't know how to access the service at this point in the script.
component: this.userService.isAdmin ? AdminComponent : UserComponent,
You can do it like this in HomeComponent:
HTML:
<admin-component *ngIf="isAdmin; else userHome;"></admin-component>
<ng-template #userHome>
<user-component></user-component>
</ng-template>
TS:
class HomeComponent {
public isAdmin: boolean;
constructor(userService: UserService) {
this.isAdmin = userService.isAdmin;
}
}
I have route configuration set up via #NgModule. And I have a service that identifies what parts of the application should be shown for the user depending on certain conditions. I need to call that service and setup the routes according to the returned value.
Problem: Route configuration is setup inside an annotation and I can't get how to call the service in such setup.
To be more specific here is the example configuration I want to enhance.
My current routing setup:
const appRoutes: Routes = [
{
path: '',
redirectTo: 'first-route',
pathMatch: 'full'
},
{
path: 'first-route',
component: FirstComponent,
pathMatch: 'full'
},
{
path: 'second-route',
component: SecondComponent,
pathMatch: 'full'
},
...
];
#NgModule({
imports: [RouterModule.forChild(appRoutes)],
exports: [RouterModule]
})
export class MyRoutingModule {
}
The service that should change the route setup:
#Injectable()
export class MyService {
getAccessibleRoutes(): Observable<string[]> {...}
}
Question: How can I make a service call and change the routes?
Note: I also looked on "Dynamically adding routes in Angular" and "How we can add new routes dynamically into RouterModule(#NgModule imports)" but I haven't found clear answer there.
If I correctly understood your problem, I think you probably can consider using route guards to reach you goal. I suggest you to use guards feature to specify the conditions of accessing your routes, instead of changing the list of routes.
Please check this link for more information about route guards:
https://codecraft.tv/courses/angular/routing/router-guards/
I hope this will help you.
import { Injectable } from '#angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '#angular/router';
import { YourSecurityService } from './your-security.service';
#Injectable()
export class YourRouteGuardService implements CanActivate {
constructor(
private router: Router,
private yourSecurityService: YourSecurityService) {
}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
console.log(state.url); // HERE YOU CAN GET REQUESTED ROUTE
if (this.yourSecurityService.checkIfUserHaveAccess())
return true;
this.router.navigate(['your-route-to-redirect']);
return false;
}
}
Next you should apply your guard to your route:
const appRoutes: Routes = [
{
path: 'someroute',
component: RouteComponent,
canActivate: [YourRouteGuardService]
},
...
]