netdjw
netdjw

Reputation: 6007

Bootstrap 5 tooltip not working in Angular 11 project

I try to use Bootstrap 5.0.2 in an Angular 11 project with this code:

index.html

<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
  <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
  <meta http-equiv="Pragma" content="no-cache">
  <meta http-equiv="Expires" content="0">
  <title>My Project</title>
  <base href="/">
  <meta http-equiv="content-language" content="en-US" />

  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
  <script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</head>
<body>
  <app-root></app-root>
</body>
</html>

In a component:

<a class="btn btn-primary"
  data-bs-toggle="tooltip"
  data-bs-html="true"
  data-bs-placement="top"
  [title]="myTitle | toHtmlEntity"
  [href]="myUrl">

  {{ myButtonLabel }}
</a>

No error message, but the tooltip is not working. The title string showed up when the mouse hover the link.

Any idea what I missed?

Upvotes: 5

Views: 12569

Answers (7)

Vinsmoke Sanji
Vinsmoke Sanji

Reputation: 1

You can just use this in ngAfterViewInit. It works for me:

const exampleEl = document.getElementById('tool') as HTMLDivElement;
const tooltip = new bootstrap.Tooltip(exampleEl, {
    animation: true,
    trigger:"hover",
    title:"Need Help?",
})

Upvotes: 0

Ganesh Bhosale
Ganesh Bhosale

Reputation: 2120

Best way for this is to create a Attribute Directive.

Install Bootstrap

npm install bootstrap

Import Bootstrap SCSS in styles.scss

// For Setting Project Specific Bootstrap Variable. Like $primary Color
@import "assets/scss/variables.scss";

// Import Bootstrap
@import "../node_modules/bootstrap/scss/bootstrap.scss";

// App Specific components
@import "assets/scss/app.scss";

Import Bootstrap Bundle JS in angular.json -> architect -> build -> options

"scripts": [
  "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
]

Declare boostrap as global variable in src/typings.d.ts. Create this file if doesn't exists.

declare var bootstrap: any;

Create a directive Tooltip:

src/app/_components/tooltip.directive.ts

import { AfterViewInit, Directive, ElementRef, OnDestroy } from '@angular/core';

@Directive({
  selector: '[bTooltip]'
})
export class TooltipDirective implements AfterViewInit, OnDestroy {
  private tooltip: any;

  constructor(private elementRef: ElementRef) {}

  ngAfterViewInit() {
    const domElement: HTMLElement = this.elementRef.nativeElement;
    this.tooltip = new bootstrap.Tooltip(domElement);
  }

  ngOnDestroy(): void {
    this.tooltip.dispose();
  }
}

src/app/_components/tooltip.directive.spec.ts

import { ElementRef } from '@angular/core';
import { TooltipDirective } from './tooltip.directive';

describe('TooltipDirective', () => {
  it('should create an instance', () => {
    const elementRefMock: ElementRef = {} as ElementRef;
    const directive = new TooltipDirective(elementRefMock);
    expect(directive).toBeTruthy();
  });
});

Declare Tooltip directive in src/app/app.module.ts:

import { TooltipDirective } from './_components/tooltip.directive';

@NgModule({
  declarations: [
    ...
    TooltipDirective
  ]
})

Use the directive as below:

<a bTooltip title="Your Message"></a>

Now you will be able to use Tooltip with all it's attributes like data-bs-placement.

I think with similar approach you can use most of the Bootstrap components in Angular.

Upvotes: 2

liahus
liahus

Reputation: 29

People here are asking whether we need to add that method in all the classes where we implement the bootstrap tooltip. There are a couple of solutions that I think will work

  1. We could use Router Events in the app component and subscribe to that and once we are finished rendering child components then run this logic. e.g in the ngOnInit app component use the below code

    this.routerEvents.subscribe((event: Event) => { if(event instanceOf NavigationEnd) { Array.from(document.querySelectorAll('button[data-bs- toggle="tooltip"]')) .forEach(tooltipNode => new bootstrap.Tooltip(tooltipNode)) }

    })

  2. use directive and use logic there using renderer2 and ElementRef, but make sure instead of using document and Array just use renderer2 and ElementRef

example here with directive

       <button type="button" appTooltip="Tooltip Data" class="btn btn-secondary me-2">
                  Hover on me
       </button>
    
      import { AfterViewInit, Directive, ElementRef, Input, Renderer2 } from '@angular/core';
declare var bootstrap: any;


@Directive({
  selector: '[appTooltip]'
})
export class BootstrapTooltipInitDirective implements AfterViewInit {

  constructor(private el: ElementRef, private renderer: Renderer2) { }

  @Input() placement = 'top';
  @Input() appTooltip = '';

  ngAfterViewInit(): void {
    this.renderer.setAttribute(this.el.nativeElement, 'data-bs-toggle', 'tooltip');
    this.renderer.setAttribute(this.el.nativeElement, 'data-bs-placement', this.placement);
    this.renderer.setAttribute(this.el.nativeElement, 'title', this.appTooltip);
    new bootstrap.Tooltip(this.el.nativeElement);
  }

}

Upvotes: 0

You could check if your <button> or <a> tag is inside an *ngIf condition. That happened in my case. Example:

<a *ngIf="conditionVariable" [routerLink]="['/home']" class="btn btn-primary btn-sm">BUTTON</a>

or

<div *ngIf="conditionVariable">
    <a [routerLink]="['/home']" class="btn btn-primary btn-sm">BUTTON</a>
</div>

In case you have it like this, you should replace it with something like:

<a [hidden]="conditionVariable" [routerLink]="['/home']" class="btn btn-primary btn-sm">BUTTON</a>

or

<div [hidden]="ConditionVariable">
    <a [routerLink]="['/home']" class="btn btn-primary btn-sm">BUTTON</a>
</div>

Upvotes: 0

Marc Thomann
Marc Thomann

Reputation: 176

package.json

"@popperjs/core": "^2.10.2",    
"bootstrap": "^5.1.3",

angular.json

 "scripts": [
   "node_modules/@popperjs/core/dist/umd/popper.min.js",
   "node_modules/bootstrap/dist/js/bootstrap.min.js",
 ],

app.service.ts

declare var bootstrap: any;

private tooltipList = new Array<any>();

enableTooltip() {
  // Bootstrap tooltip initialization
  const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
  const tooltipListNewTooltips = tooltipTriggerList.map(tooltipTriggerEl => {
    return new bootstrap.Tooltip(tooltipTriggerEl);
  });
  this.tooltipList.push(...tooltipListNewTooltips);
}

hideAllTooltips() {
  this.tooltipList;
  for (const tooltip of this.tooltipList) {
    tooltip.dispose();
  }
  this.tooltipList = new Array<any>();
}

Upvotes: 1

FoxDie
FoxDie

Reputation: 156

To add on @yatinsingla's answer, don't forget to add

declare var bootstrap: any

at the top of your component class, just below the imports.

So you have:

import {} from "....";
....
declare var bootstrap: any;

export class YourComponent implements OnInit, <other interfaces> {       
    ngOnInit(): void {
        // Bootstrap tooltip initialization
        var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
        var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
        return new bootstrap.Tooltip(tooltipTriggerEl)
        })       
    }
}

If you need to initizalize bootstrap 5's popovers, add the javascript initialization code (just copy it from the bootstrap's docs) in the ngOnInit() function the same was as for the tooltips.

Upvotes: 9

yatinsingla
yatinsingla

Reputation: 442

try writing this code in your ts file:

var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
  return new bootstrap.Tooltip(tooltipTriggerEl)
})

source: https://getbootstrap.com/docs/5.0/components/tooltips/#example-enable-tooltips-everywhere

Upvotes: 0

Related Questions