angularbootstrap-tabs

Remove active class from bootstrap tabs from component in Angular


This is my products dashboard.html

   <nav #nav>
    <div class="nav nav-tabs" id="nav-tab" role="tablist">
      <button class="nav-link active" id="nav-categories-tab" data-bs-toggle="tab" data-bs-target="#nav-categories" type="button" role="tab" aria-controls="nav-categories" aria-selected="true" (click)="showCategories()" [ngClass]="{ 'active':activeTab==='categories'}">Categories</button>     
      <button class="nav-link" id="nav-product-lists-tab" data-bs-toggle="tab" data-bs-target="#nav-product-lists" type="button" role="tab" aria-controls="nav-product-lists" aria-selected="false"(click)="showProducts()" [ngClass]="{ 'active':activeTab==='products'}">Products</button>
      <button class="nav-link" id="nav-product-details-tab" data-bs-toggle="tab" data-bs-target="#nav-product-details" type="button" role="tab" aria-controls="nav-product-details" aria-selected="false" (click)="showProductDetails()" [ngClass]="{ 'active':activeTab==='product-details'}">Product Details</button>
     </div>
  </nav>

This is my products dashboard component

    export class ProductsDashboardComponent {
    activeTab = 'categories';
    constructor(private router:Router, private route: ActivatedRoute){}
    showCategories(){
      this.router.navigate(['categories'],{relativeTo: this.route})
    }
    showProducts(){
      this.router.navigate(['products'],{relativeTo: this.route})
    }
    showProductDetails(){
      this.activeTab = 'product-details';
      this.router.navigate(['product-details'],{relativeTo: this.route})
    }
  }

Now when I click product details tab the previous tab which is products tab also shown as active as shown below. So, how do I make the other tabs class inactive.

enter image description here


Solution

  • Here is a better way to sync the active child, this will even work when we refresh the screen, we can subscribe to router events preferably NavigationEnd and then get the current firstChild path. Also the fix to your problem might be removing the active class from the html

    full code

    import { CommonModule } from '@angular/common';
    import { Component } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    import {
      ActivatedRoute,
      provideRouter,
      Router,
      RouterModule,
      NavigationEnd,
    } from '@angular/router';
    import { filter } from 'rxjs/operators';
    import 'zone.js';
    import { CategoriesComponent } from './categories/categories.component';
    import { ProductDetailsComponent } from './product-details/product-details.component';
    import { ProductsComponent } from './products/products.component';
    
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [CommonModule, RouterModule],
      template: `
        <nav #nav>
        <div class="nav nav-tabs" id="nav-tab" role="tablist">
          <button class="nav-link" id="nav-categories-tab" data-bs-toggle="tab" data-bs-target="#nav-categories" type="button" role="tab" aria-controls="nav-categories" aria-selected="true" (click)="showCategories()" [ngClass]="{ 'active':activeTab==='categories'}">Categories</button>     
          <button class="nav-link" id="nav-product-lists-tab" data-bs-toggle="tab" data-bs-target="#nav-product-lists" type="button" role="tab" aria-controls="nav-product-lists" aria-selected="false" (click)="showProducts()" [ngClass]="{ 'active':activeTab==='products'}">Products</button>
          <button class="nav-link" id="nav-product-details-tab" data-bs-toggle="tab" data-bs-target="#nav-product-details" type="button" role="tab" aria-controls="nav-product-details" aria-selected="false" (click)="showProductDetails()" [ngClass]="{ 'active':activeTab==='product-details'}">Product Details</button>
         </div>
         <router-outlet/>
      </nav>
      `,
    })
    export class App {
      activeTab = 'categories';
      constructor(private router: Router, private route: ActivatedRoute) {
        this.router.events.pipe(
          filter(event => event instanceof NavigationEnd)
        ).subscribe(() => {
          this.activeTab = this.route?.snapshot?.firstChild?.routeConfig?.path.split("/")[0] || '';
        })
      }
      showCategories() {
        this.router.navigate(['categories'], { relativeTo: this.route });
      }
      showProducts() {
        this.router.navigate(['products'], { relativeTo: this.route });
      }
      showProductDetails() {
        this.router.navigate(['product-details'], { relativeTo: this.route });
      }
    }
    
    bootstrapApplication(App, {
      providers: [
        provideRouter([
          { path: 'categories', component: CategoriesComponent },
          { path: 'products', component: ProductsComponent },
          { path: 'product-details', component: ProductDetailsComponent },
          { path: '', redirectTo: 'categories', pathMatch: 'full' },
        ]),
      ],
    });
    

    stackblitz