Twitter Bootstrap 3 dropdown menu disappears when used with prototype.js
Solution 1
I've also used code from here: http://kk-medienreich.at/techblog/magento-bootstrap-integration-mit-prototype-framework but without a need to modify any source. Just put code below somewhere after prototype and jquery includes:
(function() {
var isBootstrapEvent = false;
if (window.jQuery) {
var all = jQuery('*');
jQuery.each(['hide.bs.dropdown',
'hide.bs.collapse',
'hide.bs.modal',
'hide.bs.tooltip',
'hide.bs.popover',
'hide.bs.tab'], function(index, eventName) {
all.on(eventName, function( event ) {
isBootstrapEvent = true;
});
});
}
var originalHide = Element.hide;
Element.addMethods({
hide: function(element) {
if(isBootstrapEvent) {
isBootstrapEvent = false;
return element;
}
return originalHide(element);
}
});
})();
Solution 2
Late to the party, but found this github issue which links to this informational page which links to this jsfiddle which works really nicely. It doesn't patch on every jQuery selector and is, I think, the nicest fix by far. Copying the code here to help future peoples:
jQuery.noConflict();
if (Prototype.BrowserFeatures.ElementExtensions) {
var pluginsToDisable = ['collapse', 'dropdown', 'modal', 'tooltip', 'popover'];
var disablePrototypeJS = function (method, pluginsToDisable) {
var handler = function (event) {
event.target[method] = undefined;
setTimeout(function () {
delete event.target[method];
}, 0);
};
pluginsToDisable.each(function (plugin) {
jQuery(window).on(method + '.bs.' + plugin, handler);
});
};
disablePrototypeJS('show', pluginsToDisable);
disablePrototypeJS('hide', pluginsToDisable);
}
Solution 3
Very late to the party: if you don't feel like having extra scripts running, you can add a simple CSS override to prevent it from getting hidden.
.dropdown {
display: inherit !important;
}
Generally the use of !important
in CSS is advised against, but I think this counts as an acceptable use in my opinion.
Solution 4
Using the * selector with jQuery is not advised. This takes every DOM object on the page and puts it in the variable. I would advice to select the elements that use a Bootstrap component specific. Solution below only uses the dropdown component:
(function() {
var isBootstrapEvent = false;
if (window.jQuery) {
var all = jQuery('.dropdown');
jQuery.each(['hide.bs.dropdown'], function(index, eventName) {
all.on(eventName, function( event ) {
isBootstrapEvent = true;
});
});
}
var originalHide = Element.hide;
Element.addMethods({
hide: function(element) {
if(isBootstrapEvent) {
isBootstrapEvent = false;
return element;
}
return originalHide(element);
}
});
})();
Solution 5
see http://kk-medienreich.at/techblog/magento-bootstrap-integration-mit-prototype-framework/.
It's quite an easy fix to validate the namespace of the element clicked.
Add a validation function to prototype.js:
and after that, validate the namespace before the element will be hidden:
hide: function(element) {
element = $(element);
if(!isBootstrapEvent)
{
element.style.display = 'none';
}
return element;
},
MWD
Updated on June 06, 2022Comments
-
MWD almost 2 years
I have an issue when using bootstrap 3 & prototype.js together on a magento website.
Basically if you click on the dropdown menu (Our Products) & then click on the background, the dropdown menu (Our Products) disappears (prototype.js adds "display: none;" to the li).
Here is a demo of the issue: http://ridge.mydevelopmentserver.com/contact.html
You can see that the dropdown menu works like it should without including prototype.js on the page at the link below: http://ridge.mydevelopmentserver.com/
Has anyone else ran into this issue before or have a possible solution for the conflict?
EASY FIX:
Just replace Magento's prototype.js file with this bootstrap friendly one:
You can see the changes made in the prototype.js file to fix the bootstrap issue here:
https://github.com/zikula/core/commit/079df47e7c1f536a0d9eea2993ae19768e1f0554
NOTE: JQuery must be include in your magento skin before prototype.js.. Example:
<script type="text/javascript" src="/js/jquery.js"></script> <script type="text/javascript" src="/js/prototype/prototype.js"></script> <script type="text/javascript" src="/js/lib/ccard.js"></script> <script type="text/javascript" src="/js/prototype/validation.js"></script> <script type="text/javascript" src="/js/scriptaculous/builder.js"></script> <script type="text/javascript" src="/js/scriptaculous/effects.js"></script> <script type="text/javascript" src="/js/scriptaculous/dragdrop.js"></script> <script type="text/javascript" src="/js/scriptaculous/controls.js"></script> <script type="text/javascript" src="/js/scriptaculous/slider.js"></script> <script type="text/javascript" src="/js/varien/js.js"></script> <script type="text/javascript" src="/js/varien/form.js"></script> <script type="text/javascript" src="/js/varien/menu.js"></script> <script type="text/javascript" src="/js/mage/translate.js"></script> <script type="text/javascript" src="/js/mage/cookies.js"></script> <script type="text/javascript" src="/js/mage/captcha.js"></script>
-
Anthony almost 10 yearsThank you so much for this solution. Are there any other events apart from
hide()
which may potentially conflict? -
Janith Chinthana almost 10 yearsit is giving an error at
all.on.....
line as,TypeError: all.on is not a function
-
evgeny.myasishchev over 9 years@Anthony I haven't found any so far, have you?
-
Ananth over 9 years@evgeny.myasishchev , Thank you, this code works for me. But when i click the menu, its not redirecting to the particular page.
-
Phil almost 9 yearsI like not using '*'. On the flip side, this issue affects other twitter bootstrap functionality like popover. So, multiple elements have to be selected; albeit not all.
-
Justin over 8 yearsThis is the best solution. Very easy to understand what it is doing and makes sense to go into your existing no-conflict js file if you're already using jquery.
-
Chris Watts over 8 yearsIn case this conflicts with intended functionality of Prototype, refine the selector with
.nav .dropdown
-
medoingthings over 8 yearsModifying a library is always bad advice. You won’t be able to update jQuery without modifying the new version. If you forget to update it, things will break. Your modifications might break even more things than you fixed.
-
James Long over 8 yearsThe highest-rated answer is replacing functionality from PrototypeJS. I don't see how modifying jQuery is any more dangerous or any worse advice. As an aside, I can't remember the last time I updated a library without a serious overhaul and a simple unit test would show-up the missing modification.
-
medoingthings over 8 yearsIndeed, the highest rated answer is changing prototype.js. While this is still not ideal, the changes are tightly scoped to the Bootstrap issue (if you look at the diff mentioned within the answer). Your approach changes jQuery functionality globally, which is much more error prone than the approach from @MWD. Btw: as far as I can tell, @CJxD’s answer seems to be the most elegant one, since it doesn’t add JavaScript events to every single DOM element. Once again the highest rated answer might not be the best answer that everyone else should go for. TLDR: Be careful with changing libraries.
-
Jeff Yates about 8 yearsTrue Gold, Sir. Thanks very much!
-
Debakant Mohanty about 8 yearsThanks evgeny, the solution works for me! You made my day!
-
Thomas Harding almost 8 yearsAbsolutely brilliant. My company use a custom framework based on bootstrap, which we're starting to port into Magento. I was pulling my hair out for days when neither the dropdown, tab nor modal worked properly. Thank you SO much!