1
votes

Outline

My simple Angular SPA is using Angular Material components. My app.component template displays a mat-tab-nav-bar with a few links to place feature components within the router-outlet. One of these components (Reports) is part of a feature Module and the reports.component template has its own mat-tab-nav-bar forming a sub-menu. Here's an image of the menu:

Example Menu

All of the routing for the main tabs correctly display their respective components, including the Reports component which displays its own set of Reports tabs. All of the Reports tabs also correctly display their respective components.

My problem, as depicted in my image, is that when Reports is selected in the main menu, the Ink Bar does not animate to be beneath the selected tab, it remains at the last tab selected.

Code

Here are the Angular dependencies as defined in my package.json:

"@angular/animations": "^5.2.0",
"@angular/cdk": "5.2.2",
"@angular/common": "^5.2.0",
"@angular/compiler": "^5.2.0",
"@angular/core": "^5.2.0",
"@angular/flex-layout": "2.0.0-rc.1",
"@angular/forms": "^5.2.0",
"@angular/http": "^5.2.0",
"@angular/material": "5.2.2",
"@angular/platform-browser": "^5.2.0",
"@angular/platform-browser-dynamic": "^5.2.0",
"@angular/platform-server": "^5.2.0",
"@angular/router": "^5.2.0",

My app.component template includes the following mat-tab-nav-bar:

<nav id="tabNavBar" #tabNavBar mat-tab-nav-bar>
  <a mat-tab-link
     *ngFor="let link of navLinks"
     [routerLink]="link.path"
     routerLinkActive
     [routerLinkActiveOptions]="{exact: true}"
     #rla="routerLinkActive"
     [active]="rla.isActive"
     style="height: 64px;">
       {{ link.label }}
  </a>
</nav>

The app.component code is as follows:

import { Component, OnInit } from '@angular/core';
import { INavLink } from "./core/interfaces";

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {

  title = 'app';
  versionNumber: string = "";
  navLinks: INavLink[] = [
    { label: 'Home', path: '/home' },
    { label: 'Data Entry', path: '/data-entry' },
    { label: 'Reports', path: '/reports' },
    { label: 'Campaigns', path: '/campaigns' },
    { label: 'Utilities', path: '/utilities' }
  ];

  ngOnInit() {

    // Set the version number.
    this.versionNumber = '0.0.1';

  };
}

I have defined the app level routing code in app-routing.module.ts:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { HomeComponent } from './home/components/home.component';
import { DataEntryComponent } from './data-entry/components/data-entry.component';
import { ReportsComponent } from './reports/components/reports.component';
import { CampaignsComponent } from './campaigns/components/campaigns.component';
import { UtilitiesComponent } from './utilities/components/utilities.component';

const appRoutes: Routes = [
  { path: '', component: HomeComponent, pathMatch: 'full' },
  { path: 'home', component: HomeComponent },
  { path: 'data-entry', component: DataEntryComponent },
  { path: 'reports', component: ReportsComponent },
  { path: 'campaigns', component: CampaignsComponent },
  { path: 'utilities', component: UtilitiesComponent }
];

@NgModule({
  imports: [
    RouterModule.forRoot(
      appRoutes,
      { enableTracing: true } // <-- debugging purposes only
    )
  ],
  exports: [
    RouterModule
  ]
})
export class AppRoutingModule { }

If I remove the child navigation, including the router-outlet, from my reports.component the Ink-Bar does animate as expected beneath the Reports tab.

Here is my reports.module.ts code:

import { NgModule } from "@angular/core";
import { Routes, RouterModule } from '@angular/router';
import { CommonModule } from "@angular/common";

/* Angular Material */
import { MaterialModule } from '../core/material.module';

/* Components */
import { ReportsComponent } from './components/reports.component';
import { ReportsDesignChangesComponent } from './components/reports-design-changes.component';
import { ReportsEquipmentComponent } from './components/reports-equipment.component';
import { ReportsStationComponent } from './components/reports-station.component';

export const reportsRoutes: Routes = [
  {
    path: 'reports', component: ReportsComponent,
    children: [
      { path: '', redirectTo: 'design-changes', pathMatch: 'full' },
      { path: 'design-changes', component: ReportsDesignChangesComponent },
      { path: 'equipment', component: ReportsEquipmentComponent },
      { path: 'station', component: ReportsStationComponent }
    ]
  }
]

@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild(reportsRoutes),
    MaterialModule
  ],
  declarations: [
    ReportsComponent,
    ReportsDesignChangesComponent,
    ReportsEquipmentComponent,
    ReportsStationComponent
  ],
  exports: [RouterModule],
  entryComponents: [
    ReportsComponent,
    ReportsDesignChangesComponent,
    ReportsEquipmentComponent,
    ReportsStationComponent
  ]
})
export class ReportsModule {
}

My reports.component.html template includes the following mat-tab-nav-bar:

  <nav id="reportsNavBar" mat-tab-nav-bar color="primary" style="background-color: hsla(230, 80%, 50%, 0.2);">
    <a mat-tab-link
       *ngFor="let link of reportNavLinks"
       [routerLink]="link.path"
       routerLinkActive
       [routerLinkActiveOptions]="{exact: true}"
       #rla="routerLinkActive"
       [active]="rla.isActive"
       style="height: 64px;">
      {{link.label}}
    </a>
  </nav>

The reports.component.ts code is very simple:

import { Component } from '@angular/core';
import { RouterLinkActive } from '@angular/router';
import { INavLink } from "../../core/interfaces";

@Component({
  templateUrl: './reports.component.html',
  styleUrls: ["./reports.component.scss"]
})
export class ReportsComponent {

  reportNavLinks: INavLink[] = [
    { label: 'Design Changes', path: 'design-changes' },
    { label: 'Station', path: 'station' },
    { label: 'Equipment', path: 'equipment' }
    ]
}

Summary

Probably a very simple error on my behalf which is preventing the Ink-Bar from moving to be beneath the Reports tab, I just can't see it. I would be very grateful if someone can provide some advise to point me in the right direction.

1

1 Answers

1
votes

After many many hours of looking at this, just after posting the question I work it out!

The mat-tab-nav-bar in my app.component template specified:

[routerLinkActiveOptions]="{exact: true}"

Of course the URL will not be exactly http://localhost:5000/reports because the child routing will add an additional part to the URL such as http://localhost:5000/reports/equipment. So, I set the exact of routerLinkActiveOptions to false and everything worked fine.

I hope this helps someone else.