I have followed the following to install bootstrap 4 into my Angular 2 project: Accepted Answer, following the first 1,2,3 and 4 steps
However when I add the following <
Some plugins and CSS components depend on other plugins. If you include plugins individually, make sure to check for these dependencies in the docs. Also note that all plugins depend on jQuery (this means jQuery must be included before the plugin files).
In .angular-cli.json
add the following lines to the scripts section:
# version 4.x
"scripts": [
"../node_modules/jquery/dist/jquery.js",
"../node_modules/bootstrap/dist/js/bootstrap.js",
]
Checkout definition here
Inspired by Rahul Talar's first version(Step 1 - Crate new angular directive in ng-boostrap-dropdown.directive.ts), i've made some similar using Rendere2
import { Directive, HostListener, ElementRef, Renderer2, OnInit } from '@angular/core';
@Directive({
selector: '[appDropdown]'
})
export class AppDropdownDirective implements OnInit {
private isShow = false;
private classShow = 'show';
private parentNode: HTMLElement;
private siblingNode: HTMLElement;
constructor(private elementRef: ElementRef, private renderer: Renderer2) {}
ngOnInit() {
this.parentNode = this.renderer.parentNode(this.elementRef.nativeElement);
this.siblingNode = this.renderer.nextSibling(this.elementRef.nativeElement);
}
@HostListener('click') open() {
this.isShow = !this.isShow;
if (this.isShow) {
this.addClass();
} else {
this.removeClass();
}
}
@HostListener('document:click', ['$event']) clickout(event) {
if (this.elementRef.nativeElement !== event.target && this.isShow) {
this.removeClass();
this.isShow = false;
}
}
private addClass() {
this.renderer.addClass(this.parentNode, this.classShow);
this.renderer.addClass(this.siblingNode, this.classShow);
}
private removeClass() {
this.renderer.removeClass(this.parentNode, this.classShow);
this.renderer.removeClass(this.siblingNode, this.classShow);
}
}
Like Andrien's said, you can simplify the code like this.
constructor(private _el: ElementRef) { }
@HostBinding('class.show') isOpen = false;
@HostListener('click') toogleOpen() {
this.isOpen = !this.isOpen;
this._el.nativeElement.querySelector('.dropdown-menu').classList.toggle('show')
}
The CSS needs to be in the <head></head>
tag.
I quote from bootstrap
Copy-paste the stylesheet
<link>
into your<head>
before all other stylesheets to load our CSS.
I continue quoting
Add our JavaScript plugins, jQuery, and Tether near the end of your pages, right before the closing tag. Be sure to place jQuery and Tether first, as our code depends on them.
Make sure that you have in this way here is the link to bootstrap documentation where i get this quotes https://v4-alpha.getbootstrap.com/getting-started/introduction/
and check this answer in the post that you share the link https://stackoverflow.com/a/39809447/3284537
With Angular 8 and Bootstrap 4.2 this is the working solution I'm using :
1- First I've created a custom directive. What it does is listen to the on click event of the dropdown container and toggle the .show class of the .dropdown-menu element (Bootstrap 4 standard behavior). Also, it will close the dropdown menu if there's a click everywhere else on the document.
import {Directive, ElementRef, HostBinding, HostListener, OnInit} from '@angular/core';
@Directive({
selector: '[appDropdown]'
})
export class DropdownDirective implements OnInit {
dropDownMenu: HTMLElement;
@HostListener('document:click', ['$event']) toggleOpen(event: Event) {
if ( this.dropDownButton.nativeElement.contains(event.target) ) {
this.dropDownMenu.classList.toggle('show');
} else {
this.dropDownMenu.classList.remove('show');
}
}
constructor(private dropDownButton: ElementRef) { }
ngOnInit(): void {
this.dropDownMenu = this.dropDownButton.nativeElement.querySelector('.dropdown-menu');
}
}
2- Once your directive is created and registered. Be sure to apply the directive to the dropdown element, like on this example:
<div class="btn-group" appDropdown>
<button type="button" class="btn btn-primary dropdown-toggle">Dropdown menu<span class="caret"></span></button>
<ul class="dropdown-menu">
<li class="dropdown-item"><a href="#">Item One</a></li>
<li class="dropdown-item"><a href="#">Item Two</a></li>
<li class="dropdown-item"><a href="#">Item Three</a></li>
</ul>
</div>
I am using theme which is not build for Angular and it contain classic bootstrap, I had same issue and fixed by modifying bootstrap.js file.
Issue is that bootstrap listen events with $(document).on and problem is in "document" part.
In my bootstrap file it is line 18001
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
$(document).on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.MENU, Dropdown._dataApiKeydownHandler).on(Event.CLICK_DATA_API + " " + Event.KEYUP_DATA_API, Dropdown._clearMenus).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
event.preventDefault();
event.stopPropagation();
Dropdown._jQueryInterface.call($(this), 'toggle');
}).on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function (e) {
e.stopPropagation();
});
Change $(document) to $("body") and it will work.
$("body").on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.MENU, Dropdown._dataApiKeydownHandler).on(Event.CLICK_DATA_API + " " + Event.KEYUP_DATA_API, Dropdown._clearMenus).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
event.preventDefault();
event.stopPropagation();
Dropdown._jQueryInterface.call($(this), 'toggle');
}).on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function (e) {
e.stopPropagation();
});