diff --git a/js/src/dropdown/dropdown.js b/js/src/dropdown/dropdown.js index fbf782a0e1a5eac0eb821271d24f071e24b575ef..fc51f443cf002b0f5560babfb5b91d0aeb42c014 100644 --- a/js/src/dropdown/dropdown.js +++ b/js/src/dropdown/dropdown.js @@ -155,10 +155,6 @@ class Dropdown { // Disable totally Popper.js for Dropdown in Navbar if (!this._inNavbar) { - /** - * Check for Popper dependency - * Popper - https://popper.js.org - */ if (typeof Popper === 'undefined') { throw new TypeError('Bootstrap\'s dropdowns require Popper.js (https://popper.js.org)') } @@ -251,7 +247,7 @@ class Dropdown { EventHandler.off(this._element, EVENT_KEY) this._element = null this._menu = null - if (this._popper !== null) { + if (this._popper) { this._popper.destroy() this._popper = null } @@ -259,7 +255,7 @@ class Dropdown { update() { this._inNavbar = this._detectNavbar() - if (this._popper !== null) { + if (this._popper) { this._popper.scheduleUpdate() } } @@ -440,6 +436,10 @@ class Dropdown { toggles[i].setAttribute('aria-expanded', 'false') + if (context._popper) { + context._popper.destroy() + } + dropdownMenu.classList.remove(ClassName.SHOW) parent.classList.remove(ClassName.SHOW) EventHandler.trigger(parent, Event.HIDDEN, relatedTarget) diff --git a/js/src/dropdown/dropdown.spec.js b/js/src/dropdown/dropdown.spec.js index 963b8d9161b74979bf8269599b5c5649eb186cdf..b025ed42327214dc861deea51b9a741f530a2b51 100644 --- a/js/src/dropdown/dropdown.spec.js +++ b/js/src/dropdown/dropdown.spec.js @@ -147,6 +147,44 @@ describe('Dropdown', () => { dropdown.toggle() }) + it('should destroy old popper references on toggle', done => { + fixtureEl.innerHTML = [ + '<div class="first dropdown">', + ' <button href="#" class="firstBtn btn" data-toggle="dropdown" aria-expanded="false">Dropdown</button>', + ' <div class="dropdown-menu">', + ' <a class="dropdown-item" href="#">Secondary link</a>', + ' </div>', + '</div>', + '<div class="second dropdown">', + ' <button href="#" class="secondBtn btn" data-toggle="dropdown" aria-expanded="false">Dropdown</button>', + ' <div class="dropdown-menu">', + ' <a class="dropdown-item" href="#">Secondary link</a>', + ' </div>', + '</div>' + ].join('') + + const btnDropdown1 = fixtureEl.querySelector('.firstBtn') + const btnDropdown2 = fixtureEl.querySelector('.secondBtn') + const firstDropdownEl = fixtureEl.querySelector('.first') + const secondDropdownEl = fixtureEl.querySelector('.second') + const dropdown1 = new Dropdown(btnDropdown1) + const dropdown2 = new Dropdown(btnDropdown2) + + firstDropdownEl.addEventListener('shown.bs.dropdown', () => { + expect(firstDropdownEl.classList.contains('show')).toEqual(true) + spyOn(dropdown1._popper, 'destroy') + dropdown2.toggle() + done() + }) + + secondDropdownEl.addEventListener('shown.bs.dropdown', () => { + expect(dropdown1._popper.destroy).toHaveBeenCalled() + done() + }) + + dropdown1.toggle() + }) + it('should toggle a dropdown and add/remove event listener on mobile', done => { fixtureEl.innerHTML = [ '<div class="dropdown">',