Can't Toggle Navbar in Bootstrap 4 in Angular
Asked Answered
C

11

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"
  }
}
Compressive answered 30/8, 2017 at 3:17 Comment(2)
How are you including your dependencies in your angular app?Ferd
@cwanjt. Can you check again my angular-cli?Compressive
F
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.

Ferd answered 30/8, 2017 at 3:39 Comment(6)
I only installed the npm install --save [email protected]Compressive
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.Ferd
In .angular-cli.json scripts, add the path for bootstrap.min.jsFerd
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"Trollope
As per previous comment, answer should be edited to show 'popper.js' rather than 'popperjs'Conferva
I installed them again but still have problem. attribute data-toggle is not allowed here, attribute data-target is not allowed here, attribute aria-controls is not allowed here, attribute aria-expanded is not allowed here, attribute aria-label is not allowed here, attribute placeholder is not allowed here,Shrimp
H
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 {}
Hippogriff answered 1/9, 2017 at 14:27 Comment(5)
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.Gaygaya
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 collapsedToulouse
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.Sash
This also really really helpedBarhorst
This is really helpful!Robbyrobbyn
F
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.

Ferd answered 30/8, 2017 at 3:39 Comment(6)
I only installed the npm install --save [email protected]Compressive
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.Ferd
In .angular-cli.json scripts, add the path for bootstrap.min.jsFerd
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"Trollope
As per previous comment, answer should be edited to show 'popper.js' rather than 'popperjs'Conferva
I installed them again but still have problem. attribute data-toggle is not allowed here, attribute data-target is not allowed here, attribute aria-controls is not allowed here, attribute aria-expanded is not allowed here, attribute aria-label is not allowed here, attribute placeholder is not allowed here,Shrimp
B
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>
Brachium answered 23/10, 2017 at 6:33 Comment(1)
Thanks for sharing this. It should be the preferred way in an Angular app! Kudos!Curley
R
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>
Rokach answered 2/2, 2019 at 15:54 Comment(2)
very useful, thumbs up ... no need for extra libraries :) ... The thing only is missing, "animation" ;(Fucus
Attribute data-toggle is not allowed here!?Shrimp
L
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

Levo answered 2/11, 2019 at 9:58 Comment(0)
T
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;
}
Thracophrygian answered 13/12, 2020 at 18:1 Comment(0)
M
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();
   }
}
Mcguire answered 22/11, 2019 at 13:30 Comment(0)
J
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.

Jeramey answered 27/2, 2020 at 5:50 Comment(0)
P
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.

Popover answered 24/9, 2018 at 20:35 Comment(0)
T
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

Tow answered 27/12, 2019 at 2:59 Comment(0)
D
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

Decathlon answered 6/5, 2020 at 12:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.