Puede que alguna vez hayais tenido que usar conjuntamente Bootstrap, JQuery y Prototype por requerimientos del front de vuestro proyecto. En mi caso, en la aplicación en la que estoy actualizando la versión de jQuery y Bootstrap, se utilizan unas custom tags llamadas AjaxTags que hacen uso de Prototype.js y Scriptaculous.js para su correcto funcionamiento.
Cuando usamos conjuntamente estas librerías o frameworks, algunos de sus plugins pueden entrar en conflicto y provocar errores que pueden ser basante molestos y difíciles de detectar.
Tras mucho depurar Javascript pude localizar que los eventos de Prototype entraban en conflicto con Boostrap y los menús padre desaparecían al hacer clic en los items de menú o incluso al hacer click fuera del menú. Me puse a investigar un poco más y tras googlear un poco, me encontré con que había características de Bootstrap que dejaban de funcionar correctamente como:
- Los componentes plegables rebotan de manera disruptiva debido a los efectos.
- Los menús desplegables padre desaparecen al cerrar el hijo.
- El disparador de información sobre herramientas / padre desaparece en el desenfoque.
- El activador de popover / padre desaparece al desenfocar o alternar.
- Las pestañas desaparecen al disparar un evento (trigger) y al hacer toggle.
Con la mayoría de estos problemas, lo que ocurre es que Prototype.js aplica display: none;
al elemento padre, haciéndolo desaparecer.
Para solucionarlo, puedes insertar el siguiente código tras cargar jQuery y antes de que lo haga Prototype
jQuery.noConflict(); if (Prototype.BrowserFeatures.ElementExtensions) { 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); }); }, pluginsToDisable = ['collapse', 'dropdown', 'modal', 'tooltip', 'popover']; disablePrototypeJS('show', pluginsToDisable); disablePrototypeJS('hide', pluginsToDisable); }
Con el código anterior evitaremos esos errores que parecen inexplicables y que como todo en esta vida tienen una explicación.