Angular 4.x and Beyond – Twitter Bootstrap Nav Bar Not Working in Mobile

Yesterday, I have deployed my personal site into production which is built with Angular 4.x using an old template (Twitter Bootstrap 2.x). I just recently noticed that the navigation menu is not expanding when viewed in smaller screens. It is due to the fact that I didn’t include the Bootstrap JS files.

HTML Structure

Below is the HTML structure of the nav bar menu:

<div class="navbar navbar-fixed-top">
  <div class="navbar-inner">
    <div class="container">
      <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </a>
      <a class="brand goTop" routerLink="/">Brand</a>
      <div class="nav-collapse pull-right">
        <ul class="nav">
          <li routerLinkActive="active">
            <a routerLink="/about">About</a>
          </li>
          <li routerLinkActive="active">
            <a routerLink="/projects">Projects</a>
          </li>
        </ul>
      </div>
    </div>
  </div>
</div>

It looks like the typical old-school Twitter Bootstrap navigation menus. However, since I cannot include the bootstrap JS files, the menu won’t expand/collapse when toggled on small screens.

Micmic Nav Bar Behavior Using Component

The solution was derived from this article from AngularFirebase. Since my Bootstrap version is way older, I have to mimic the old behavior of the plugin and convert it to Angular Component.

By default, on small screens, the .nav-collapse container is hidden. When toggled to expand, the .collapse class is added to the container with style height: auto;. We can now convert this whole Nav Bar into a component and make the collapse toggle work using TypeScript!

src/app/navbar/navbar.component.html:

<div class="navbar navbar-fixed-top">
  <div class="navbar-inner">
    <div class="container">
      <a class="btn btn-navbar" (click)="toggleCollapse()">
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </a>
      <a class="brand goTop" routerLink="/">Brand</a>
      <div class="nav-collapse pull-right" [class.collapse]="collapse">
        <ul class="nav">
          <li routerLinkActive="active">
            <a routerLink="/about" (click)="selectAndClose()">About</a>
          </li>
          <li routerLinkActive="active">
            <a routerLink="/projects" (click)="selectAndClose()">Projects</a>
          </li>
        </ul>
      </div>
    </div>
  </div>
</div>

We removed some classes related to the Bootstrap JS since it is not needed anymore. We attached the click event on the Nav Bar button with the toggleCollapse() method which we shall define in our Component. We add the .collapse class when the collapse toggle is activated. We will add some styles later to add the auto height style.

We also add the selectAndClose() method so that the Nav Bar will close once the user clicks a navigation item.

src/app/navbar/navbar.component.ts:

import { Component } from '@angular/core';

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: [
    'navbar.component.css'
  ]
})

export class NavbarComponent {
  collapse = false;

  toggleCollapse(): void {
    this.collapse = !this.collapse;
  }

  selectAndClose(): boolean {
    this.collapse = false;
    return false;
  }
}

For the selectAndClose() method, we return false to prevent the browser from following the link instead of following the Angular route.

src/app/navbar/navbar.component.css:

.nav-collapse.collapse {
  height: auto;
}

Integrate the NavbarComponent

Since our NavbarComponent is ready, we can now replace the original Nav Bar with the component markup.

<app-navbar></app-navbar>

Finally, we add this to our declared modules.

import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
// Other imports...
import { NavbarComponent } from './navbar/navbar.component';

@NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    AppRoutingModule
  ],
  declarations: [
    AppComponent,
    // Other components...
    NavbarComponent
  ],
  bootstrap: [
    AppComponent
  ]
})
export class AppModule { }

What’s Missing?

Unfortunately, we don’t have the smooth sliding animation like those of Bootstrap. I can live with it but I will definitely add the animations later on, probably by using the Angular animations.

This entry was posted in Angular and tagged , . Bookmark the permalink.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *