35

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"
  }
}
2
  • How are you including your dependencies in your angular app? Commented Aug 30, 2017 at 3:20
  • @cwanjt. Can you check again my angular-cli? Commented Aug 30, 2017 at 3:25

11 Answers 11

55

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 {}
Sign up to request clarification or add additional context in comments.

5 Comments

Yes. This is exactly what I've been looking for, though I tried to avoid ng-bootstrap, seems like this solution works better than importing the popper, and jQuery.
Works with bootstrap 4 and angular 5. I created a member boolean variable isCollapsed and set that to true in ngOnInit() so it defaults to collapsed
This actually solved my issue. This should be the right answer. You also manage to get rid of JS libraries like jquery or popper.js, which shouldn't be needed in a pure Angular app.
This also really really helped
This is really helpful!
16

@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.

6 Comments

I only installed the npm install --save [email protected]
And it worked? Great if it did, and you'll still want the other two in your project, as bootstrap depends on them. You'll also want to add them to your .angular-cli.json file.
In .angular-cli.json scripts, add the path for bootstrap.min.js
This wasn't working for me because I had not installed popper.js. Thanks cwanjt. Note that my install was "npm install --save popper.js" instead of "popperjs"
As per previous comment, answer should be edited to show 'popper.js' rather than 'popperjs'
|
12

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>

1 Comment

Thanks for sharing this. It should be the preferred way in an Angular app! Kudos!
12

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>

2 Comments

very useful, thumbs up ... no need for extra libraries :) ... The thing only is missing, "animation" ;(
Attribute data-toggle is not allowed here!?
4

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

Comments

4

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;
}

Comments

1

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();
   }
}

Comments

1

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.

Comments

0

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.

Comments

0

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

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.