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) }];
Related
Im using angular and wanted to try lazy loading with multiples modules, and i getting this error Error: Cannot match any routes. URL Segment: 'home/users/profile'
So well i been like a few long hours trying to solve this problem but i foundno answer
APP MODULE
{
path: 'home',
component: HomeComponent,
loadChildren: () =>
import('./components/home/home.module').then((m) => m.HomeModule),
},
{
path: 'auth',
loadChildren: () =>
import('./components/auth/auth.module').then((m) => m.AuthModule),
},
{
path: '',
pathMatch: 'full',
redirectTo: 'home',
},
HOME ROUTING MODULE
{
path: 'users',
loadChildren: () =>
import('../users/users.module').then((m) => m.UsersModule),
},
USERS ROUTING MODULE
{
path: '',
outlet: 'child',
component: UsersComponent,
},
{
path: 'user/:id',
outlet: 'child',
component: UserComponent,
},
{
path: 'profile',
outlet: 'child',
component: ProfileComponent,
},
Here is the repo if you need to see something else https://github.com/ginebras/user-system
I don't see any need for using named outlets, you are complicating things for yourself. Let's keep it simple, So I removed 'child' from your <router-outlet> as well as removed outlet: child from your routes.
I updated your User's Routing in user-routing.module, It should look like this:
RouterModule.forChild([
{
path: '',
component: UsersComponent,
pathMatch: 'full',
},
{ path: 'profile', component: ProfileComponent },
{
path: 'user-detail/:id',
component: UserComponent,
},
]),
],
I also changed the user:/id path to user-detail:id for readability. You can change it back or you change from where you are opening user:/id to user-detail:id.
I update the stackblitz too, have a look: https://stackblitz.com/edit/angular-ivy-rmxi8g?
Welcome Alejø.
Most likely you need to remove this line
component: HomeComponent,
You need to use component or loadChildren but not both. You can put the HomeComponent as an empty path in the home routing module. Don't forget pathMatch: 'full' on all your empty paths.
I configured my app in two levels for nested routing as shown in the snapshot image.
the content of app modules is:
app.module.ts
#NgModule({
declarations: [
AppComponent,
DashboardComponent,
TeacherMembershipComponent,
StudentMembershipComponent,
RulesComponent,
ContactInfoComponent,
Page404Component,
UserProfileComponent,
NotificationsComponent,
GeneralComponent,
ReportComponent
],
// ...
and app-routing.module.ts
const routes: Routes = [
{
path: 'dashboard',
component: DashboardComponent
},
{
path: 'userProfile',
component: UserProfileComponent
},
{
path: 'general',
component: GeneralComponent
},
{
path: 'report',
component: ReportComponent
},
{
path: 'notifications',
component: NotificationsComponent
},
{
path: "department/:dep", loadChildren: () => import(`./branches/branches.module`).then(m => m.BranchesModule)},
{
path: 'aboutUs/rules',
component: RulesComponent
},
{
path: 'aboutUs/contactInfo',
component: ContactInfoComponent
},
{
path: 'membership/teacher',
component: TeacherMembershipComponent
},
{
path: 'membership/student',
component: StudentMembershipComponent
},
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
{ path: '**', component: Page404Component },
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
the second level is branches that its modules are:
branches.module.ts:
#NgModule({
declarations: [
BranchesComponent,
CoursesListComponent,
TeachersListComponent,
TeacherResumeComponent,
TeacherSelectionFormComponent,
Page404BranchesComponent
],
imports: [
CommonModule,
BranchesRoutingModule,
MaterialDesignModule
]
})
export class BranchesModule { }
and branches-routing.module.ts:
const routes: Routes = [
{ path: '', component: BranchesComponent, children: [
{
path: "coursesList/:branchCourses",
component: CoursesListComponent
},
{
path: "teacherSelection",
component: TeacherSelectionFormComponent
},
{
path: "teacherResume",
component: TeacherResumeComponent
},
{
path: 'coursesList', component: CoursesListComponent
},
{
path: '', redirectTo: 'coursesList', pathMatch: 'full'
},
{
path: '**', component: Page404BranchesComponent
},
]}
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
till here, when one of links (departments) in sidenav of app.component.html is clicked, the branches.component is loaded in place of route-outlet of app.component and subscribes the parameters passed from app.component, and lists branches respected to each link.
baranch.component.ts:
export class BranchesComponent implements OnInit {
filteredBranches$!: Observable<Branch[]>;
filteredBranches!: Branch[];
constructor(private route: ActivatedRoute, private branchesService: BranchesService) {
}
activeTab: string=''
ngOnInit(): void {
this.route.paramMap.pipe(
switchMap((params: Params) => {return this.branchesService.getDepBranches(params['get']('dep')) })
).subscribe((branches) => {this.filteredBranches = branches; this.activeTab=this.filteredBranches[0].name});
}
}
and branch.component.html:
<nav mat-tab-nav-bar>
<a mat-tab-link *ngFor="let br of filteredBranches"
[routerLink]="['coursesList', br.code]"
routerLinkActive="activeLink"
(click)="activeTab = br.name"
[active]="activeTab == br.name"> {{ br.name }} </a>
</nav>
<router-outlet></router-outlet>
but, although links of branches are listed in template of branches.component, no courses respect to each branches are shown by coursesList.component which placed in router-outlet of branches.component, because it does not received any route parameter from branch.component, until one of branch link is clicked.
I expect that upon branches links are shown at the same time branches.component is loaded, bellow of them, the courses of the first branch are listed by coursesList.component placed in router-outlet of branches.component.
Whereas no one of branch links is clicked and no parameter passed to coursesList.component, nothing is shown. Therefore, is there a solution to active the first branch link as defualt and pass its courses parameters to coursesList component upon branches.component is loaded? Best regards.
How to check which layout component currently active in Angular in app.component ?
Here Is example my app-routing.module.ts.
{
path: '',
component: FrontComponent,
children: [
{
path: '',
redirectTo: 'login',
pathMatch: 'full'
},
{
path: 'login',
component: LoginComponent
}
]
},
{
path: '',
component: MainComponent,
canActivate: [AuthGuard],
children: [
{
path: 'dashboard',
component: DashboardComponent
},
{
path: 'message-list',
component: MessageListComponent,
}
]
}
Now I want to check layout component in app.component such as if it is 'FrontComponent' or 'MainComponent' . Because I want to perform some activity based on layout component. I have searched other questions but could not get required answer. can anyone please help me out? Thanks in advance.
Specifically looking to check layout frontcomponent is active in app.component.ts
You can learn it by looking at the URL with
import { Component } from '#angular/core';
import { Router } from '#angular/router';
#Component({
template: ''
})
export class Component {
constructor(private router: Router) {}
ngOnInit() {
if ( this.router.url.indexOf('login') != -1) {
console.log('Father is FrontComponent');
}
}
}
You can make a service where you store the current layout component name string, and this variable gets overridden when switching to the other component.
I was trying to navigate from a parent component (Core) using an url dynamically emitted from a child component (Menubar).
The problem is that the navigation is cancelled without any reason.
To find out if the problem came from the parent component, I implemented a button in the parent component navigating to a static url, and it worked!
Core template:
<app-menubar (onNavigation)="onMenubarNavigation($event)"></app-menubar>
<button type="button" (click)="navigate()">Navigate</button>
<router-outlet><router-outlet>
Core component:
onMenubarNavigation(urlSegments: string[]): void {
this.router.navigate(urlSegments);
}
navigate(): void {
let segments: string[];
segments = ['index', 'messages'];
this.router.navigate(segments);
}
Menubar template:
<a (click)="changeRoute(element.module.route)">
// element.module route is the string: "/messages"
Menubar component:
#Output() onNavigation = new EventEmitter<string[]>();
changeRoute(url: string): void {
let urlSegments: string[];
urlSegments = url.split('/');
urlSegments[0] = 'index';
this.onNavigation.emit(urlSegments);
}
App routing module:
const routes: Routes = [
{ path: 'login', loadChildren: '.\/auth\/auth.module#AuthModule' },
{ path: 'logout', loadChildren: '.\/auth\/auth.module#AuthModule' },
{ path: '', loadChildren: './theme/core/app.core.module#AppCoreModule', pathMatch: 'full' },
];
#NgModule({
imports: [RouterModule.forRoot(routes, { enableTracing: true })],
exports: [RouterModule]
})
export class AppRoutingModule { }
Core routing module:
const coreRoutes: Routes = [
{
path: '',
component: AppCoreComponent,
canActivate: [AuthGuard],
children: [
{
path: 'home',
loadChildren: '..\/home\/app.home.module#AppHomeModule'
},
{
path: 'index',
loadChildren: '..\/index\/app.index.module#AppIndexModule'
},
{
path: '',
redirectTo: 'index',
pathMatch: 'full'
}
]
}
];
#NgModule({
imports: [
RouterModule.forChild(coreRoutes)
],
exports: [
RouterModule
]
})
export class AppCoreRoutingModule {}
The angular routing debug shows that both urls are the same during navigation, using the one emitted by the child component or the static one, but when I navigate using the one emitted, the navigation is cancelled and I have no idea why...
Has someone ever encoutered this kind of trouble with the angular router?
I have a problem with Angular routing. I have main app routing module and sub module with its own routing module and router-outlet but routes defined in this submodule are shown using root router outlet and not the child one.
My folder structure:
My code listings
app-routing.module.ts
const routes: Routes = [
{ path: '', component: HomeComponent, pathMatch: 'full' }
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
app.component.html
<router-outlet></router-outlet>
home-routing.module.ts
const routes: Routes = [
{ path: '', component: LandingPageComponent},
{ path: 'register', component: RegisterComponent },
{ path: 'login', component: LoginComponent }
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class HomeRoutingModule { }
home.component.html
...
<div class="inner cover">
<router-outlet></router-outlet>
</div>
...
That's what I get when I use empty path - it opens home component properly.
But when i enter /register i get plain html from login.component.html without template in home.component.html file
EDIT
I added name to child outlet
<router-outlet name="home"></router-outlet>
Changed route names to:
const routes: Routes = [
{ path: '', component: LandingPageComponent, outlet: 'home'},
{ path: 'register', component: RegisterComponent, outlet: 'home' },
{ path: 'login', component: LoginComponent, outlet: 'home' }
];
Now I got that error:
EDIT 2
I try to access those routes in 2 ways:
A link(which may be incorrect):
<a routerLink="/login">Log In</a></li>
Or typing manually:
localhost:4200/login
In Angular 2, router outlets can be named:
<router-outlet>
<router-outlet name="children"></router-outlet>
</router-outlet>
App:
const routes: Routes = [
{ path: '', component: HomeComponent, pathMatch: 'full' }
];
Home:
const routes: Routes = [
{ path: '', component: LandingPageComponent, outlet: 'children'},
{ path: 'register', component: RegisterComponent, outlet: 'children' },
{ path: 'login', component: LoginComponent, outlet: 'children' }
];
You can even define child routes:
const routes: Routes = [
{ path: '',
component: HomeComponent,
pathMatch: 'full', children: [
{ path: '', component: LandingPageComponent, outlet: 'children'},
{ path: 'register', component: RegisterComponent, outlet: 'children' },
{ path: 'login', component: LoginComponent, outlet: 'children' }
]
}
];
http://onehungrymind.com/named-router-outlets-in-angular-2/
If you want those 3 components to be rendered inside of the HomeComponent in a named outlet, then you need to define the following routes:
const routes: Routes = [
{ path: '',
component: HomeComponent,
pathMatch: 'full'
},
{ path: 'landing', component: LandingPageComponent, outlet: 'children'},
{ path: 'register', component: RegisterComponent, outlet: 'children' },
{ path: 'login', component: LoginComponent, outlet: 'children' }
];
And inside of app.component.html add the named router outlet
....//html template
<router-outlet name="children"></router-outlet>
....//html template
EDIT 1:
To navigate to the named outlets you need to use the following routed links:
//inside of home.component.html
<a [routerLink]="[{ outlets: { children: ['login'] } }]">Take me to login!</a>
The generated link will look like:
root/(children:login)
More info in the following link to the docs
EDIT 2:
I changed the original routes and the component template where the named outlet is added. Why?
it is not possible, as far as I know, to have a named outlet with an empty path (''). The empty path tells angular that the named outlet is empty (no component is currently rendered in it).
I believe your problem has to do with declarations. I can not know for certain since you didn't show the code in your app.module.ts and home.module.ts file and have not tested this fully myself.
A component needs to be declared inside the module connected to the template with the desired routing outlet. In your case the login component would need to be added to "declarations" in your home.module.ts file and removed from "declarations" in the app.module.ts file.
Angular does not seem allow you to reuse the same component in multiple routing-outlets unless they are in the same template, since it would cause an error stating "x component declared in multiple modules".