Skip to content

Instantly share code, notes, and snippets.

@Disane87
Last active March 3, 2020 08:40
Show Gist options
  • Save Disane87/9a21a94831677ab5288dba03d26a9322 to your computer and use it in GitHub Desktop.
Save Disane87/9a21a94831677ab5288dba03d26a9322 to your computer and use it in GitHub Desktop.
medium-disane-angular-router-tabs-routes
<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>
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;
}
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 { }
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