8
votes

I'm trying to create a dropdown item in a Bootstrap navbar using Angular 6. My code is working when I test it online :

<nav class="navbar bg-light navbar-light navbar-expand">
<ul class="navbar-nav">
  <li class="nav-item dropdown" >
    <a class="nav-link dropdown-toggle" data-toggle="dropdown">Page1</a>
    <div class="dropdown-menu">
      <a class="dropdown-item" href="#">Page1.1</a>
    </div>
  </li>
  <li><a class="nav-link" href="#">Page2</a></li>
</ul>
</nav>

But the dropdown does not work with Angular 6. I've used the following method in order to use Bootstrap with Angular :

ng add @ng-bootstrap/schematics

And everything works fine except for that dropdown item !

8
Can you please tell me which version of bootstrap are you using? - Flutterian
Also requesting you to please add "node_modules/bootstrap/dist/css/bootstrap.min.css" inside styles array in angular.json file - Flutterian
You can try angular dropdown instead of bootstrap. You can refer to the following link. It is multi-functional npmjs.com/package/@ng-select/ng-select - Shridhar Acharya

8 Answers

23
votes

I have came across the same problem earlier and I found as below:

  1. html should be binded with the class container in bootstrap as mentioned in Bootstrap Layout
  2. Dropdowns are built on a third party library Popper.js as mentioned in Bootstrap Dropdown

As far as I know from your problem that you haven't refer to the required javascript i.e. util.js, bootstrap.js, popper.js or minified version.

Here, I have done nothing much, just refer the required javascript files in the index file

<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>

And I created a nav component and design as required like this:

<div class="container">
    <!-- Content here -->
    <ul class="nav nav-pills">
        <li class="nav-item">
            <a class="nav-link active" href="#">Active</a>
        </li>
        <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">Dropdown</a>
            <div class="dropdown-menu">
                <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 class="dropdown-divider"></div>
                <a class="dropdown-item" href="#">Separated link</a>
            </div>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="#">Link</a>
        </li>
        <li class="nav-item">
            <a class="nav-link disabled" href="#">Disabled</a>
        </li>
    </ul>
</div

The working demo can be found here. Hope this helps you.

8
votes

I have faced the same issue of bootstrap, but I got the solution. If you are using Angular 6, then no need to add popper.js for bootstrap. You need to add bootstrap 4 and then add rxjs-compat.

npm install rxjs-compat

And add ngx-bootstrap to perform dropdown action. Install the ngx-bootstrap,

npm install ngx-bootstrap --save

now we need to add the dropdown module from ngx-bootstrap in your application using following code

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
import { TooltipModule } from 'ngx-bootstrap/tooltip';
import { ModalModule } from 'ngx-bootstrap/modal';
import { AppComponent } from './app.component';

@NgModule({
 declarations: [
   AppComponent
 ],
 imports: [
   BrowserModule,
   CommonModule,
   BsDropdownModule.forRoot(),
   TooltipModule.forRoot(),
   ModalModule.forRoot()
 ],
 providers: [],
 bootstrap: [AppComponent]
})
export class AppModule { }

then I did some changes in your code and it's working fine for me.

<nav class="navbar navbar-default">
<ul class="nav navbar-nav">
  <li class="dropdown" dropdown >
    <a dropdownToggle role="button"> <!-- {2} -->
        Page1<span class="caret"></span></a>
    <div *dropdownMenu class="dropdown-menu">
      <a class="dropdown-item" href="#">Page1.1</a>
    </div>
  </li>
  <li><a class="nav-link" href="#">Page2</a></li>
</ul>
</nav>
6
votes

The answer of @Rushikesh Salunke is great but at the time i saw it i was already using @ng-bootstrap library, not ngx, and this is what i found from the docs.

First, import the NgbDropdown Module into the component where you want to use it.

import { NgbDropdown} from '@ng-bootstrap/ng-bootstrap';

Then modify your .html as follows:

<div ngbDropdown class="d-inline-block">
  <button class="btn btn-outline-primary" id="dropdownBasic1" ngbDropdownToggle>Toggle dropdown</button>
  <div ngbDropdownMenu aria-labelledby="dropdownBasic1">
    <button class="dropdown-item">Action - 1</button>
    <button class="dropdown-item">Another Action</button>
    <button class="dropdown-item">Something else is here</button>
  </div>
</div>

You can see other use cases here.

2
votes

Here you go...

I did below changes -

1. app.component.html

<p>
  Start editing to see some magic happen :)
</p>
<nav class="navbar bg-light navbar-light navbar-expand">
<ul class="nav navbar-nav">
  <li class="dropdown" appDropdown>
    <a href="#" class="dropdown-toggle" role="button">Page1</a>
    <ul class="dropdown-menu">
      <li><a href="#">Page1.1</a></li>
      <li><a href="#">Page1.2</a></li>
      <li><a href="#">Page1.3</a></li>
    </ul>
  </li>
  <li><a class="nav-link" href="#">Page2</a></li>
</ul>
</nav>

2. app.module.ts

I have added one directive to listen click event for dropdown and imported same in app.module.ts

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

import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';

import { DropdownDirective } from './dropdown.directive';

@NgModule({
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent, HelloComponent, DropdownDirective ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

3. dropdown.directive.ts

Added directive to listen click event

import { Directive, HostListener, ElementRef, Renderer2 } from "@angular/core";

@Directive({
  selector: '[appDropdown]'
})

export class DropdownDirective {
  manageDropdown : boolean = false;

  constructor(private elementRef: ElementRef, private renderer: Renderer2)   {

  }

  @HostListener('click') openDropdown(eventData: Event) {
    if(!this.manageDropdown) {
      this.renderer.addClass(this.elementRef.nativeElement,'open');
      this.manageDropdown = !this.manageDropdown;
    } else {
      this.renderer.removeClass(this.elementRef.nativeElement, 'open');
      this.manageDropdown = !this.manageDropdown;
    }
  }
}

4. angular.json

Requesting you to do "npm install --save bootstrap@3" and do below changes in angular.json file.

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

Note - For your reference please visit reference link. You can see the dropdown demo.

0
votes

When you do everything right and follow the examples given, and it doesn't seem to work, it can be that you forgot to import Bootstrap Module.

You can do this by this line to your main module in which you intend to use the component:

import { NgbModule } from '@ng-bootstrap/ng-bootstrap'

@NgModule({
  declarations: [MyComponent],
  imports: [
    NgbModule
  ],
  exports: [MyComponent]
})
0
votes
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>


<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
crossorigin="anonymous"></script>


<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
crossorigin="anonymous"></script>

Adding this in index.html before closing body tag. This works for me.

 <ul class="navbar-nav navbar-right">
        <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" role="button" data-toggle="dropdown" aria-haspopup="true"
                aria-expanded="false">
                Manage Data
            </a>
            <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                <a class="dropdown-item" href="">Save Data</a>
                <a class="dropdown-item" href="">Fetch Data</a>
            </div>
        </li>
    </ul>
0
votes

Step 1: install ng-bootstrap

ng add @ng-bootstrap/ng-bootstrap

Step 2: Add ng-bootstrap module to your component module file

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

...

@NgModule({
  imports: [BrowserModule, NgbModule],
  ...
})

Step 3: In your component view file add the following code:

<div class="col">
    <div ngbDropdown class="d-inline-block">
      <button class="btn btn-outline-primary" id="dropdownBasic1" ngbDropdownToggle>Toggle dropdown</button>
      <div ngbDropdownMenu aria-labelledby="dropdownBasic1">
        <button ngbDropdownItem>Action - 1</button>
        <button ngbDropdownItem>Another Action</button>
        <button ngbDropdownItem>Something else is here</button>
      </div>
    </div>
  </div>

Ref: ng-bootstrap Docs

-1
votes

For anyone who is looking for solution with bootstrap 4.4.1 and Angular 9+, i solved by creating custom directive with following host listener. just adding show to parent li was not doing anything

 @HostListener('click', ['$event']) onClick(event) {
         if (this.el.nativeElement.classList.contains('show')) {
            this.renderer.removeClass(this.el.nativeElement, 'show');
            this.renderer.setAttribute(this.el.nativeElement.childNodes[0], 'aria-expanded', 'false')
            this.renderer.removeClass(this.el.nativeElement.childNodes[1], 'show')

        } else {
            this.renderer.addClass(this.el.nativeElement, 'show')
            this.renderer.setAttribute(this.el.nativeElement.childNodes[0], 'aria-expanded', 'true')
            this.renderer.addClass(this.el.nativeElement.childNodes[1], 'show')
        }
    }