Last active
March 3, 2020 08:40
-
-
Save Disane87/9a21a94831677ab5288dba03d26a9322 to your computer and use it in GitHub Desktop.
medium-disane-angular-router-tabs-routes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="d-flex container-fluid flex-row h-100"> | |
<div class="navigation m-3"> | |
<ul class="nav flex-column nav-pills"> | |
<li class="nav-item" [class.pt-3]="!first" *ngFor="let route of routes; let first = first;"> | |
<a class="nav-link" routerLinkActive="active" [routerLinkActiveOptions]="{exact:true}" [routerLink]="route.path">{{route.component.name }}</a> | |
</li> | |
</ul> | |
</div> | |
<div class="tab container flex-fill h-100 px-0 bg-white border-bottom d-flex flex-column"> | |
<!-- All tabs --> | |
<ul class="nav nav-tabs bg-light mt-3"> | |
<li class="nav-item" *ngFor="let tab of tabs; let first = first;" (mouseleave)="mouseOverTab(null)" | |
(mouseenter)="mouseOverTab(tab)"> | |
<div class="nav-link" [class.active]="tab.active"> | |
<div class="d-flex flex-row cursor-pointer"> | |
<span class="badge badge-danger my-auto mr-2" *ngIf="(tab.count | async) > 0">{{ tab.count | async}}</span> | |
<div class="flex-fill" [routerLink]="tab.route.path">{{ tab.name }}</div> | |
<div class="transition-all-ease-250ms" | |
[style.width]="currentHoverTabKey == tab.key ? 'auto': '0px'" | |
[class.pl-3]="currentHoverTabKey == tab.key" | |
[class.opacity-0]="currentHoverTabKey != tab.key" | |
[class.invisible]="currentHoverTabKey != tab.key" *ngIf="tabs.length > 1" | |
(click)="disposeTab(tab)">X</div> | |
</div> | |
</div> | |
</li> | |
</ul> | |
<!-- Content of one tab (and all other non visible) --> | |
<div class="tab-content p-3 border-left border-right flex-fill"> | |
<ng-container *ngFor="let tab of tabs"> | |
<div class="tab-pane fade {{tab.name}}" [class.show]="tab.active" [class.active]="tab.active" | |
[id]="tab.name" role="tabpanel"> | |
<!-- --> | |
<ng-container *ngComponentOutlet="tab.component;"></ng-container> | |
</div> | |
</ng-container> | |
</div> | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
Component, | |
ChangeDetectionStrategy, | |
ChangeDetectorRef, | |
} from "@angular/core"; | |
import { | |
Router, | |
RoutesRecognized, | |
Route | |
} from "@angular/router"; | |
@Component({ | |
selector: "my-app", | |
templateUrl: "./app.component.html", | |
styleUrls: ["./app.component.css"], | |
changeDetection: ChangeDetectionStrategy.OnPush | |
}) | |
export class AppComponent { | |
public tabs: Tab[] = []; | |
public routes: Route[] = []; | |
public currentHoverTabKey: string; | |
constructor( | |
private router: Router, | |
private cd: ChangeDetectorRef | |
) { | |
// listen to routing change event to attach new tabs or activate a new one | |
router.events.subscribe(val => { | |
if (val instanceof RoutesRecognized) { | |
this.checkAndAddRouteTab(val); | |
} | |
}); | |
} | |
ngOnInit() { | |
// get all routes to mock a navigation | |
this.routes = this.router.config; | |
} | |
disposeTab(tab: Tab) { | |
if (this.tabs.length > 1) { | |
this.tabs = this.tabs.filter(item => item.key !== tab.key); | |
if (tab.active) { | |
// deactivate all tabs | |
this.deactivateTabs(); | |
this.router.navigateByUrl(this.tabs[this.tabs.length - 1].route.path); | |
} | |
} | |
} | |
mouseOverTab(tab: Tab) { | |
this.currentHoverTabKey = tab ? tab.key : null; | |
} | |
checkAndAddRouteTab(val: RoutesRecognized) { | |
// get the component to activate by the route | |
const comp = val.state.root.firstChild.component; | |
// deactivate all tabs | |
this.deactivateTabs(); | |
// check if the tab to be activated is already existing | |
if (this.tabs.find(tab => tab.name == comp["name"]) == null) { | |
// if not, push it into the tab array | |
this.tabs.push({ | |
name: comp["name"], | |
component: comp, | |
key: comp["name"], | |
active: true, | |
route: val.state.root.firstChild.routeConfig | |
}); | |
} else { | |
// if the tab exists, activate it | |
const tabToActivate = this.tabs.find(tab => tab.name == comp["name"]); | |
if (tabToActivate) { | |
tabToActivate.active = true; | |
} | |
} | |
this.cd.markForCheck(); | |
} | |
deactivateTabs() { | |
this.tabs.forEach(tab => (tab.active = false)); | |
} | |
// getTabInjector(tabKey: string): Injector { | |
// return this.tabInjectors.find(tab => tab.tabKey == tabKey).injector; | |
// } | |
} | |
// export type TabInjector = { tabKey: string; injector: Injector }; | |
export interface Tab { | |
name: string; | |
component: any; | |
active: boolean; | |
route: Route; | |
key: string; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { NgModule } from '@angular/core'; | |
import { BrowserModule } from '@angular/platform-browser'; | |
import { FormsModule } from '@angular/forms'; | |
import { RouterModule, Route } from '@angular/router'; | |
import { AppComponent } from './app.component'; | |
import { Tab1Component } from './tab1/tab1.component'; | |
import { Tab2Component } from './tab2/tab2.component'; | |
import { StartComponent } from './start/start.component'; | |
const ROUTES: Route[] = [ | |
{ path: '', component: StartComponent, pathMatch: 'full' }, | |
{ path: 'tab1', component: Tab1Component }, | |
{ path: 'tab2', component: Tab2Component }, | |
]; | |
@NgModule({ | |
imports: [ BrowserModule, FormsModule, RouterModule.forRoot(ROUTES) ], | |
declarations: [ AppComponent, Tab1Component, Tab2Component, StartComponent ], | |
bootstrap: [ AppComponent ], | |
providers: [] | |
}) | |
export class AppModule { } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export interface Tab { | |
name: string; | |
component: any; | |
active: boolean; | |
route: Route; | |
key: string; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment