I have two menu collapse on my bootstrap theme 3, I want:
When one of the collapse menu is open, the other one closes.
When one of the collapse menu is opened, the page behind becomes unclear.
When one of the collapse menu is open, the scrolling of the page behind is blocked.
When one of the collapse menu is open, the click of the back page is blocked.
My problem :
When collapse is closed the body's "overlay-is-navbar-collapse" class is not deleted. Why ?
Here is my code :
(function ($) {
var $document = $(document);
var $body = $(document.body);
// Wrap everything in a DOM ready handler.
$document.ready(function () {
// Save the navbar collapse selectors so making updates/tracking easier.
var navbarCollapseFirst = '#navbar-collapse-first';
var navbarCollapseSecond = '#navbar-collapse-second';
var navbarCollapseBoth = navbarCollapseFirst + ',' + navbarCollapseSecond;
// Save the jQuery instances (for performance).
var $navbarCollapseFirst = $(navbarCollapseFirst);
var $navbarCollapseSecond = $(navbarCollapseSecond);
// Variable for saving which navbar collapse is currently open.
var $open = $();
// For performance reasons, bind evens directly on the document. jQuery
// allows you to pass a targeting selector between the event and handler
// so it will only call said handler when the event matches said selector.
$document
// Bind "show" event for first navbar collapse.
.on('show.bs.collapse', navbarCollapseBoth, function (e) {
// Indicate that the first is open.
$open = $(e.target);
// Collapse the first if it's not the one that just opened.
if (!$navbarCollapseFirst.is($open)) {
$navbarCollapseFirst.collapse('hide');
}
// Collapse the second if it's not the one that just opened.
else if (!$navbarCollapseSecond.is($open)) {
$navbarCollapseSecond.collapse('hide');
}
// Add the body class.
$body.addClass('overlay-is-navbar-collapse');
})
// Bind "hide" event for first navbar collapse.
.on('hide.bs.collapse', navbarCollapseFirst, function (e) {
// Indicate that the first is open.
var $hide = $(e.target);
// Remove the first as the opened navbar collapse.
if ($navbarCollapseFirst.is($hide) && $navbarCollapseFirst.is($open)) {
$open = $();
}
// Remove the second as the opened navbar collapse.
else if ($navbarCollapseSecond.is($hide) && $navbarCollapseSecond.is($open)) {
$open = $();
}
// Remove the body class if there is no open navbar collapse.
if (!$open[0]) {
$body.removeClass('overlay-is-navbar-collapse');
}
});
});
})(window.jQuery);
Related
I have an overlay menu that I need to shut when clicking on the links. I have some event listeners but it doesn't work on the links. The menu event used on the burger icon works, the menuItems is for the links that doesn't work. I need it to also work with Pjax link
I have tried target the a tags like menuItems = document.querySelectorAll('.__overlay_nav_content_list_item a'); but it does not work.
(function($) {
"use strict";
var app = function() {
var body = undefined;
var menu = undefined;
var menuItems = undefined;
var init = function init() {
body = document.querySelector('body');
menu = document.querySelector('.burger_menu_icon');
menuItems = document.querySelectorAll('.__overlay_nav_content_list_item');
applyListeners();
};
var applyListeners = function applyListeners() {
menu.addEventListener('click', function() {
return toggleClass(body, '__overlay_nav-active');
});
menuItems.addEventListener('click', function() {
return toggleClass(body, '__overlay_nav-active');
});
};
var toggleClass = function toggleClass(element, stringClass) {
if (element.classList.contains(stringClass))
element.classList.remove(stringClass);
else element.classList.add(stringClass);
};
init();
}();
})(jQuery);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Have you checked event bubbling? If menuItems are descendants of menu, clicking the menu items will trigger menuItems.addEventListener('click', function() { and hence toggle the class, then the event will bubble up to menu and trigger menu.addEventListener('click', function() {, removing the class you just added. So the end result is that it looks like nothing changed.
If that is the issue, only use the click event on menu, or stop the bubbling up of the event of the menuItems by using event.stopPropagation().
Although i would prefer only using the click event of the menu, first try:
Keep in midn that querySelectorAll() returns a nodeList, so it's an arraylike object containing all the links, not a single link.
Array.from( menuItems ).forEach(function( menuItem ) {
menuItem.addEventListener('click', function( event ) { // add event here so you have access to it!
event.stopPropagation(); // call stopPropagation() first
return toggleClass(body, '__overlay_nav-active'); // Once you return, the function stops.
});
});
so we know that this is the problem or not. Do not forget to add event as the parameter for the event handler function.
I am required to write a Jasmine.js test to test a menu icon for what will happen when it is clicked, (the menu bar slides in when it is clicked for the first time, and out when it is clicked for the second time which it does, but my test fails to demonstrate it)
I came up with this idea but the spec-runner shows (expected false to be true). any help on what could be the problem?
describe('The menu', function () {
/* TODO: Write a test that ensures the menu changes
* visibility when the menu icon is clicked. This test
* should have two expectations: does the menu display when
* clicked and does it hide when clicked again.
*/
it('the menu changes visibility when the menu icon is clicked', function () {
var menuIconClicked, menuChangesWhenClicked = false,
menuChangesWhenClickedAgain = false;
$(".menu-icon-link").click(function(){
var $this = $(this);
$(this).data('clicked', true);
if($(this).data('clicked')) {
menuIconClicked=true // if menu icon is clicked, set the menuIconClicked value to true
if (menuIconClicked && $('body').hasClass(null)) {
menuChangesWhenClicked=true;
}
}
if($this.data('clicked') && menuIconClicked===true) {
menuIconClicked=false // if menu icon is clicked when it already has been clicked aka menuIconClicked===true
if (!menuIconClicked && $('body').hasClass('menu-hidden')) {
menuChangesWhenClickedAgain=true;
}
}
});
expect(menuChangesWhenClicked).toBe(true);
expect(menuChangesWhenClickedAgain).toBe(true);
});
});
It looks like you are already using Jasmine and JQuery, so I would suggest using also the jasmine-jquery.js library to help you with tracking states?
This was a good reference: Testing That A DOM Event Was Fired
To get the code below to work, just include jasmine-jquery.js in your project folder, link the <\script> via your index.html's <\head> and your set. Hope this helps.
describe('The menu', function() {
// Add a spyOnEvent
let spyEvent, menu;
beforeEach(function() {
// I assumed your menu icon has a unique ID of 'menuIconID'
// so I passed onto a spy listener.
spyEvent = spyOnEvent('#menuIconID', 'click');
});
it('the menu changes visibility when the menu icon is clicked', function() {
// Click once
$("#menuIconID").trigger("click");
expect('click').toHaveBeenTriggeredOn('#menuIconID');
expect(spyEvent).toHaveBeenTriggered();
menu = $('body').attr('class'); // assign the new class
expect(menu).toBe('');
// Click again
$("#menuIconID").trigger("click");
expect('click').toHaveBeenTriggeredOn('#menuIconID');
expect(spyEvent).toHaveBeenTriggered();
menu = $('body').attr('class'); // update the new class
expect(menu).toBe('menu-hidden');
});
});
I have some tabs. All are collapsed by default. If the user click on a button first tab opens. I figured out that part:
jQuery(document).ready(function() {
jQuery('#showFirstTab').on('click', function() {
var tabObj = jQuery('#podcast-tabs li:first a');
tabObj.tab('show');
var programId = tabObj.data('programid');
jQuery('#calendar-' + programId).fullCalendar('render');
});
});
Now I need to check if any tab is open, and click again on the same button, all tabs should collapse. I was thinking in use a variable to save the state, but not sure if library provides already a solution for this.
You can first check if any tab is open, by using the tabsactivate event:
var isActive = false;
$(".podcast-tabs").on("tabsactivate", function( event, ui ) {
isActive = true;
});
Now, inside your click code check for that variable and if true close all tabs using option like:
if (isActive)
$("#podcast-tabs").tabs("option", "active", false);
is it possible to close a bootstrap popover when you click outside the popover but when you click inside the popover it stays open. I know this has been discussed before in here but this one also closes when you click inside the popover.
Here is their demo: http://jsfiddle.net/Sherbrow/e6Gt8/
var $poped = $('.poped');
$poped.popover();
// Trigger for the popover
$poped.each(function() {
var $this = $(this);
$this.on('hover',function() {
var popover = $this.data('popover');
var shown = popover && popover.tip().is(':visible');
if(shown) return; // Avoids flashing
$this.popover('show');
});
});
// Trigger for the hiding
$('html').on('click.popover.data-api',function() {
$poped.popover('hide');
});
Have a look at http://jsfiddle.net/VcwUm/
// Trigger for the hiding
$('html').on('click.popover.data-api',function(e) {
if($(e.target).has('.poped').length == 1){
$poped.popover('hide');
} else {
return false;
}
});
All I'm doing is checking if the target element has a child with a certain class to decide if I should close the popup or not.
Similar to this question, but taking it a step further. I would like to detect clicks outside of a set of items, which I am handling in the following way:
$('#menu div').live('click', function() {
// Close other open menu items, if any.
// Toggle the clicked menu item.
$('body').one('click', function(event) {
// Hide the menu item.
event.stopPropagation();
});
});
This works like a charm, unfortunately, when another menu item is open and a
second is clicked, it requires two clicks to open the second item. The first
click hides the first menu item that was open, the second shows the second menu
item.
The "correct" behavior works in the following way:
Clicking a menu item opens it.
Clicking the same menu item (or it's children) closes it.
Clicking another menu item closes the first, opens the second.
Clicking away from (open) menu items closes them.
I have tried the following in place of the above $('body').one() order to ignore clicks on menu items with little success:
// Captures click on menu items in spite of the not.
$('*').not('#menu *').one('click', function() { // Hide menu }
$('*:not(#menu)').one('click', function() { // Hide menu }
As always, thanks for any help!
Just move the body click handler outside and do something like this:
$('body').bind('click', function(e) {
if($(e.target).closest('#menu').length == 0) {
// click happened outside of menu, hide any visible menu items
}
});
It was incorrectly pointed out in the comments that e.target does not work in IE; this is not true as jQuery's Event object fixes these inconsistencies where necessary (IE, Safari).
I wrote this a long time ago, before the glory days of jQuery...
function clickedOutsideElement(elemId) {
var theElem = getEventTarget(window.event);
while(theElem != null) {
if(theElem.id == elemId)
return false;
theElem = theElem.offsetParent;
}
return true;
}
function getEventTarget(evt) {
var targ = (evt.target) ? evt.target : evt.srcElement;
if(targ != null) {
if(targ.nodeType == 3)
targ = targ.parentNode;
}
return targ;
}
document.onclick = function() {
if(clickedOutsideElement('divTest'))
alert('Outside the element!');
else
alert('Inside the element!');
}