Joseph
Joseph

Reputation: 7755

Can't Toggle Navbar in Bootstrap 4 in Angular

Why i can't toggle navbar when resizing to mobile screen in angular 4 using bootstrap 4. I included it in the angular cli in script and styles, the node modules from bootstrap. Is there something missing in my code? Please check below. Is there something wrong? Please help

<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
  <a class="navbar-brand" href="#">Dashboard</a>
  <button class="navbar-toggler d-lg-none" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" id="navbarsExampleDefault">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Settings</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Profile</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Help</a>
      </li>
    </ul>
    <form class="form-inline mt-2 mt-md-0">
      <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
      <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
    </form>
  </div>
</nav>

.angular-cli.json

 "styles": [
    "styles.css",
     "../node_modules/bootstrap/dist/css/bootstrap.min.css"
  ],
  "scripts": [

    "../node_modules/popper.js/dist/umd/popper.min.js",
    "../node_modules/jquery/dist/jquery.min.js",
    "../node_modules/bootstrap/dist/js/bootstrap.min.js"

  ],

package.json

      {
  "name": "dashboard2",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^4.0.0",
    "@angular/common": "^4.0.0",
    "@angular/compiler": "^4.0.0",
    "@angular/core": "^4.0.0",
    "@angular/forms": "^4.0.0",
    "@angular/http": "^4.0.0",
    "@angular/platform-browser": "^4.0.0",
    "@angular/platform-browser-dynamic": "^4.0.0",
    "@angular/router": "^4.0.0",
    "bootstrap": "^4.0.0-beta",
    "core-js": "^2.4.1",
    "jquery": "^3.2.1",
    "popper.js": "^1.12.5",
    "rxjs": "^5.4.1",
    "zone.js": "^0.8.14"
  },
  "devDependencies": {
    "@angular/cli": "1.2.7",
    "@angular/compiler-cli": "^4.0.0",
    "@angular/language-service": "^4.0.0",
    "@types/jasmine": "~2.5.53",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "~6.0.60",
    "codelyzer": "~3.0.1",
    "jasmine-core": "~2.6.2",
    "jasmine-spec-reporter": "~4.1.0",
    "karma": "~1.7.0",
    "karma-chrome-launcher": "~2.1.1",
    "karma-cli": "~1.0.1",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.2",
    "ts-node": "~3.0.4",
    "tslint": "~5.3.2",
    "typescript": "~2.3.3"
  }
}

Upvotes: 35

Views: 52043

Answers (11)

Siva Rajesh
Siva Rajesh

Reputation: 71

It works absolutely fine try this one

<nav class="navbar navbar-expand-md navbar-light">
  <a>Home</a>
  <button
    class="navbar-toggler d-lg-none"
    type="button"
    data-toggle="collapse"
    (click)="isShown=!isShown"
  >
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" [ngClass]="{ 'show': isShown }">
    <ul class="navbar-nav">
      <li class="nav-item active">
        <a class="nav-link" href="#">About</a>
      </li>
    </ul>
  </div>
</nav>

Corresponding ts file is

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  // title = 'WebApp';
  isShown = false;
}

Upvotes: 4

Tejashree
Tejashree

Reputation: 810

Bootstrap - 4.4.1, Angular-cli: 7.3.9

The easiest way is to import the js bundle in your client entry point:

import 'bootstrap/dist/js/bootstrap.bundle'; line into 'polyfills.ts' file

Upvotes: 0

Dmitry Grinko
Dmitry Grinko

Reputation: 15204

If someone is looking for a way to dynamically toggle navbar you can use ViewChild with a template variable to get a reference to the button, then you can fire the click event:

HTML

<button #menu class="navbar-toggler d-lg-none" type="button"
    data-toggle="collapse" data-target="#navbarsExampleDefault"
    aria-controls="navbarsExampleDefault" aria-expanded="false"
    aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
</button>

TS

import { ViewChild, ElementRef } from '@angular/core';

@ViewChild('menu') menu: ElementRef;

toggleMenu() {
    this.menu.nativeElement.click();
}

closeMenu() {
    const isMenuOpen = this.menu.nativeElement.getAttribute('aria-expanded') === 'true';
    if (isMenuOpen) {
        this.menu.nativeElement.click();
    }
}

I know it's not an answer to this question but it's very related and might helpful.

Upvotes: 1

George Makroglou
George Makroglou

Reputation: 449

I don't know if this is still relevant but something that helped me when I faced this problem was to stop the live server and then recompile the app and start it again with ng serve. Sometimes when you install dependencies while the server is running, the dependencies are not seen by angular.json even if you insert them. Maybe for future users

Upvotes: 0

Surya R Praveen
Surya R Praveen

Reputation: 3745

This worked for me!!!

Now we can toggle navbar when resizing to mobile screen in angular 4 using bootstrap 4.

Try this code

app.component.html

<nav class="navbar navbar-expand-lg justify-content-between">
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation" id="navButton">
    <i class="fa fa-bars"></i>
  </button>
  <div class="row">
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto">
        <li class="nav-item" *ngFor="let menu of mainmenu, let i = index">
          <a class="nav-link" (click)="findIndex(i)" routerLink="/{{menu.href}}">{{menu.icon}} {{menu.text}}</a>
          <ng-container *ngIf="menu.children && menu.children.length > 0">
            <span class="d-block d-sm-none"><i class="fa fa-chevron-down" aria-hidden="true"></i></span>
          </ng-container>
          <ul class="sub_menu dropdown-menu" [ngClass]="{active : isActive(i)}" *ngIf="menu.children && menu.children.length > 0">
            <li *ngFor="let sub_menu of menu.children"><a class="nav-link" routerLink="/{{sub_menu.href}}" (click)="closeMenu()"><img src="{{sub_menu.icon}}" class="nav-img" /> {{sub_menu.text}}</a></li>
          </ul>
        </li>
      </ul>
    </div>
  </div>
</nav>

app.component.ts

closeMenu() {
    var isMobile = /iPhone|iPad|iPod|BlackBerry|Opera Mini|IEMobile|Android/i.test(navigator.userAgent);
    if (isMobile) {
      document.getElementById('navButton').click();
   }
}

Upvotes: 1

Anand Raja
Anand Raja

Reputation: 3108

to make toggle working in angular, you have to do only 4 things

  1. install ng boostrap
  2. add toggle click listener to navbar switch (click)="isCollapsed = !isCollapsed"
  3. use property bind to aria-expanded, [attr.aria-expanded]="!isCollapsed" so that property will be changed when you click(either true or false)
  4. the same way use property bind to ngCollapse [ngbCollapse]="isCollapsed"

NB: using JQuery is not adviced

Collapse nav bar without using JQuery

Upvotes: 4

Stefan
Stefan

Reputation: 518

As stated you need a property (e.g. isShown which is initially false) then use

[ngClass]="{ 'show': isShown }" 

here

<div class="collapse navbar-collapse" [ngClass]="{ 'show': isShown }" id="navbarSupportedContent" >

the click events on the links make sure the menu collapses again when a link is followed

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

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {


  isShown:boolean = false;
  constructor() { }

  ngOnInit() {
  }
  
}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <a class="navbar-brand" routerLink="/"><img width="20%" src="/assets/logo.svg"></a>
  <button #navbarToggler class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" (click)="isShown = !isShown" [attr.aria-expanded]="isShown"  aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" [ngClass]="{ 'show': isShown }" id="navbarSupportedContent" >
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" (click)="isShown = false" routerLink="/">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" (click)="isShown = false" routerLink="/contact">Contact</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" (click)="isShown = false" routerLink="/imprint">Imprint</a>
      </li>
    </ul>
  </div>
</nav>

Upvotes: 12

irhetoric
irhetoric

Reputation: 361

If you want to make Angular work with Bootstrap 4 and not use @ng-bootstrap, see the code in this git repo: https://github.com/fmorriso/Angular-bootstrap4-nav/tree/master/src/app/navigation

I burned way too much time on this. You have to hack Angular to get it to work; it isn't just a matter of incorrect versions, etc.

Upvotes: 0

Jade Cowan
Jade Cowan

Reputation: 2583

@Joseph, it looks like you haven't installed the dependencies for bootstrap (and bootstrap itself) for the navbar toggle to work.

If you open up terminal or the command line and navigate to the directory that contains your package.json file, run the following commands:

npm install --save jquery
npm install --save popper.js
npm install --save [email protected]

These commands will install the requisite dependencies for you project. They're fairly explicit in what they're doing, but if you need a refresh on what they're doing or how they work, I would suggest looking at the documentation for npm install located here.

After they're installed, you'll want to make sure you include them in your .angular-cli.json file, so you're angular app can use them.

Upvotes: 16

Philipp P
Philipp P

Reputation: 619

This example provides both, toggling functionality for the hamburger icon (in other words the whole navbar if it's running in responsive mode) as well as toggling of dropdown menu items.

It uses ng-bootstrap but I would rather go with native Bootstrap navbar support instead of doing this "hacks"!?

Obviously others struggle with the same issue: https://github.com/twbs/bootstrap/issues/24227

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <a class="navbar-brand" href="#">ApplicationName</a>
  <button class="navbar-toggler" type="button" (click)="toggleNavbar = !toggleNavbar">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" [ngbCollapse]="!toggleNavbar">
    <ul class="navbar-nav">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Features</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Pricing</a>
      </li>
      <li ngbDropdown class="nav-item">
        <a class="nav-link" id="navbarDropdownMenuLink" ngbDropdownToggle aria-haspopup="true" aria-expanded="false">
          Dropdown link
        </a>
        <div ngbDropdownMenu aria-labelledby="navbarDropdownMenuLink">
          <a class="dropdown-item" href="#">Action</a>
          <a class="dropdown-item" href="#">Another action</a>
          <a class="dropdown-item" href="#">Something else here</a>
        </div>
      </li>
    </ul>
  </div>
</nav>

Upvotes: 12

Loke
Loke

Reputation: 1065

It looks like you might have been looking at this example from Bootstrap. I did, and had the same issue.

The problem is it is not an angular example so it won't work. To make it work you have to use the (click) event and a variable. So change your template to

<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
  <a class="navbar-brand" href="#">Dashboard</a>
  <button class="navbar-toggler d-lg-none" type="button" (click)="isCollapsed = !isCollapsed" [attr.aria-expanded]="!isCollapsed" aria-controls="navbarsExampleDefault" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" id="navbarsExampleDefault" [ngbCollapse]="isCollapsed">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Settings</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Profile</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Help</a>
      </li>
    </ul>
    <form class="form-inline mt-2 mt-md-0">
      <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
      <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
    </form>
  </div>
</nav>

If you want your menu to be collapsed by default you should set the variable to true in your class (in your .ts file for the component) public isCollapsed = true;

Here's a plunker

One more thing; If your nav is in a shared module you must remember to import NgbCollapseModule here as well.

That is, your shared.module.ts should be:

import { NgModule } from '@angular/core';
import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap';
/*Plus all your other modules*/

@NgModule({
  imports: [NgbCollapseModule],
  declarations: [],
  exports: []
})
export class SharedModule {}

Upvotes: 55

Related Questions