I am working on a Dashboard layout in my current project with Angular 4+.
When the user navigates between the different sections of the app I need the navmenu header title to update to reflect the current section of the app.
As an example when the user visits settings "Page Title" should change to "Settings"
The project is based on the .net core 2 Angular template Below is the code I have to makeup the app routing as well as the dashboard routing.
navigation.service
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable()
export class NavigationService {
private titleSource = new BehaviorSubject<string>("Page Title");
currentTitle = this.titleSource.asObservable();
constructor() {
}
changeTitle(title: string) {
this.titleSource.next(title);
}
}
app-routing.module
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from "./components/home/home.component";
const appRoutes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: '**', redirectTo: 'home' }
]
@NgModule({
imports: [
RouterModule.forRoot(appRoutes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
app.module.shared
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { AppRoutingModule } from './app-routing.module';
import { DashboardModule } from "./components/dashboard/dashboard.module";
import { UtilsModule } from "./components/shared/shared.module";
//app components
import { AppComponent } from './components/app/app.component';
import { NavigationService } from "./services/navigation.service";
@NgModule({
declarations: [
AppComponent,
],
imports: [
SharedModule,
DashboardModule,
AppRoutingModule,
DevExtremeModule,
CommonModule,
HttpModule,
FormsModule
],
providers: [NavigationService]
})
export class AppModuleShared {
}
dashboard-routing.module
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DashboardComponent } from "./dashboard.component";
import { SettingsProfileComponent } from "./settings/settingsProfile/settings.profile.component";
import { SettingsEmailComponent } from "./settings/settingsEmail/settings.email.component";
import { UsersListComponent } from "./users/users.list.component";
export const dashboardRoutes: Routes = [
{
path: 'dashboard',
component: DashboardComponent,
children: [{
path: 'settings',
data: { title: 'Settings' },
children: [{
path: 'profile',
component: SettingsProfileComponent
},
{
path: 'email',
component: SettingsEmailComponent
}]
}, {
path: 'users',
data: { title: 'Users' },
children: [{
path: '',
component: UsersListComponent
}]
}]
}
];
@NgModule({
imports: [
RouterModule.forChild(dashboardRoutes)
],
exports: [RouterModule]
})
export class DashboardRoutingModule { }
dashboard.module
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { UtilsModule } from "../shared/shared.module";
import { DashboardRoutingModule } from "./dashboard-routing.module";
import { DashboardComponent } from './dashboard.component';
import { SettingsProfileComponent } from "./settings/settingsProfile/settings.profile.component";
import { SettingsEmailComponent } from "./settings/settingsEmail/settings.email.component";
import { UsersListComponent } from "./users/users.list.component";
@NgModule({
imports: [
CommonModule,
UtilsModule,
DashboardRoutingModule
],
declarations: [
DashboardComponent,
SettingsProfileComponent,
SettingsEmailComponent,
UsersListComponent,
],
providers: []
})
export class DashboardModule {
}
I am trying to avoid having a OnInit in each component. Is it possible to do this only in the routing? The project is early on so if there are any other recommendations on how to accomplish this we are open to change.
There are many ways to handle this. One possible solution is to listen to router events and based on them decide about what content should be displayed.
This approach would reguire importing navigation state first, for example, when route change ended. Like this:
import { Router, NavigationEnd } from '@angular/router';
then you need to subscirbe to that, for example like this.
constructor ( private router: Router ) {
router.events.subscribe( (event) => ( event instanceof NavigationEnd ) && this.handleRouteChange() )
}
Once you are able to detect change in navigation you can see, what route it is and based on that make further deccisions. For example like this:
handleRouteChange = () => {
if (this.router.url.includes('some_key_part_of_url') {
do what ever you want to do with your content...
}
};
You do not necessarily analyse the actual content of the url, you may decide on other router properties. Please, read the docs on router.
Another option may be a route guard/route resolver. You could add a guard/resolver to each route and have it read your data property.
Here is an example resolver:
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { IMovie } from './movie';
import { MovieService } from './movie.service';
@Injectable()
export class MovieResolver implements Resolve<IMovie> {
constructor(private movieService: MovieService,
private navigationService: NavigationService) { }
resolve(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
const title = route.data['title'];
this.navigationService.changeTitle(title);
return true;
}
}
Something like the above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With