jQuery slidetoggle keeps toggling after window resize/ready combined - javascript

I want to add slidetoggle only when screen size is less than 768px. I also want this to work when user for some reason would resize the window manually.
I have come across a bug with jQuery where my dropdown menu will keep toggling after I resize the window. I've looked up this issue and tried adding return false; to click function and adding position: relative; overflow:hidden; to toggleable div(these should be a workaround according to some forums). No luck there. What causes this bug. I will include the whole function with the click function
//Call function on ready and window resize
$(document).ready(navigationMobile);
$(window).on('resize', navigationMobile);
function navigationMobile() {
const windowWidth = $(window).width();
if (windowWidth < 768) {
//Remove href from main link and add it as a "all" link in menu
$(".js-second-title").each(function () {
const currentHref = $(this).attr('href');
$(this).removeAttr('href');
if ($(this).siblings('ul').find('.js-all-link').length === 0) {
$(this).siblings('ul').prepend(`<li><a class="js-all-link" href="${currentHref}">All</a></li>`);
}
});
//When clicked on main link open menu
$(".js-second-title").click(function () {
$(this).siblings('.js-menu').slideToggle();
$(this).toggleClass('js-open');
});
} else {
//Add href back to main link
$('.js-second-title').each(function () {
if ($(this).attr('href') === undefined) {
const allHref = $(this).siblings('ul').find('.js-all-link').attr('href');
$(this).attr('href', `${allHref}`);
$(this).siblings('ul').find('.js-all-link').remove();
}
});
}
}
Cheers!

I don't exactly know what is causing this bug. But I came up with this workaround.
//Remove href from main link and add it as a "all" link in menu
$(".js-second-title").each(function () {
$(this).addClass('js-closed');
const currentHref = $(this).attr('href');
$(this).removeAttr('href');
if ($(this).siblings('ul').find('.js-all-link').length === 0) {
$(this).siblings('ul').prepend(`<li><a class="js-all-link" href="${currentHref}">All</a></li>`);
}
});
//When clicked on main link open menu
$(document).on("click", '.js-second-title.js-closed', function (e) {
$(this).removeClass('js-closed');
$(this).siblings('.js-menu').slideDown();
$(this).addClass('js-open');
});
$(document).on("click", '.js-second-title.js-open', function (e) {
$(this).siblings('.js-menu').slideUp();
$(this).removeClass('js-open');
$(this).addClass('js-closed');
});
So here I am basically extening SlideToggle function. Before I call slide functions on click I give each js-second-title classes an extra class .js-closed so the browser is aware that the menu is closed. After that I call slideDown function when I click on closed menu title and slideUp when I click on open menu title.
I do not think that this is the best or most sematic solution so I would like to keep this topic open.

Related

How to close navbar when clicking outside of it

How can I edit my code so that the navbar closes when clicked outside of it but remain open if something inside of it is clicked?
$(document).ready(function() {
$('.nav-btn').on('click', function() {
$('.nav-btn').removeClass('active');
$(this).parent().find('.sub-menu').slideToggle();
$(this).toggleClass('active');
});
});
$(document).ready(function () {
$('.nav-btn').on('click', function (e) {
// Stop Document to be clicked when clicked in nav.
e.stopPropagation()
$('.nav-btn').removeClass('active');
var subMenu = $(this).parent().find('.sub-menu')
if (!$(".sub-menu").is(":visible")) {
$(this).parent().find('.sub-menu').slideToggle();
}
$(this).toggleClass('active');
});
// Toggle Sub Menu and remove active when Any vacant place is clicked
$(this).on('click', function (event) {
$('.nav-btn').removeClass('active');
$('.nav-btn').parent().find('.sub-menu').slideToggle();
});
// Prevent View close when Sub Items is clicked
$('.sub-menu').on('click', function (e) {
e.stopPropagation()
})
});
Hi, You just need to prevent the document click when clicked on the nav item and handle some additional things as done in the above code.
You can see Plunker example here also.
$(document).on('click', function (event) {
if ($(event.target).closest('.main-nav').length === 0) {
// Close button code
}
});
Another possible way is by wrapping all the content inside another div (except the header & navbar) and using the onclick tag:
<div onclick="hideNavbar()">
all your content goes here
</div>
function hideNavbar() {
$('.navbar-collapse').collapse('hide');
// getting the navbar div with jQuery
// and calling the function 'hide' of the Bootstrap class 'collapse'
}

Ways to combine two click functions, when one click function has a window size if statement

I'm trying to combine two click functions to condense the code, but i'm not sure how. Thanks!
$(document).ready(function () {
//when clicking on a link hide the navigation links
$('nav a').click(function () {
if ($(window).width() < 730) {
$('nav').toggleClass('showNav');
$('.navToggle').toggleClass('iconTop');
$('.navToggle').toggleClass('iconMiddle');
$('.navToggle').toggleClass('iconBottom');
}
});
//when clicking on icon hide and show the navigation links
//the icon is only visible when the screen size is less then 730px
$('.navToggle').click(function () {
$('nav').toggleClass('showNav');
$('.navToggle').toggleClass('iconTop');
$('.navToggle').toggleClass('iconMiddle');
$('.navToggle').toggleClass('iconBottom');
});
});
Would something like this work?
$('nav a, .navToggle').click(function () {
if ($(this).hasClass('navToggle') || $(window).width() < 730) {
$('nav').toggleClass('showNav');
$('.navToggle').toggleClass('iconTop iconMiddle iconBottom');
}
});
Basically, you check if the clicked element has the class .navToggle. If it doesn't, it check the window size before doing the action.

Add a click functionality to sidebar without affecting its toggle feature

I have a sidebar and I have a button which toggles the sidebar on click. I have a jQuery function which does that. I have a new functionality now, where, if the sidebar is open and the user clicks any of the list items in the sidebar, it toggles back and some function will be excecuted.
The Problem:
When I click the li inside the sidebar, the toggle button is waiting for it's second click (my guess). So if I add toggle on clicking sidebar li, the main toggle button functionality breaks. How do I keep both without affecting each other. I hope I have made myself clear. Here is the code.
JS
// code for sidebar toggle in jQuery
$.fn.toggleClick = function () {
var methods = arguments,
count = methods.length;
return this.each(function (i, item) {
var index = 0;
$(item).on('click', function () {
return methods[index++ % count].apply(this, arguments);
});
});
};
//for opening sidebar
function openSidebar() {
$('#sg-evm-sidebar').animate({
left: 0
}, 300)
$('.container').css({
position: "fixed"
}).animate({
left: 300
}, 300)
$('.content-overlay').delay(300).show();
}
//closing sidebar
function closeSidebar() {
$('#sg-evm-sidebar').animate({
left: -300
}, 300)
$('.container').css({
position: "fixed"
}).animate({
left: 0
}, 300)
$('.content-overlay').delay(300).hide();
}
//$(".empName").on("click", function () {
// closeSidebar();
//});
// calling toggleclick here
$('.toggle-box').toggleClick(openSidebar, closeSidebar);
Here is a JS FIDDLE. I created it from my huge website. So please ignore broken images.
I've updated your fiddle: http://jsfiddle.net/qvksx30g/4/
I've added some basic logic
var sidebarOpen = false;
function toggleSidebar()
{
if (sidebarOpen)
closeSidebar();
else
openSidebar();
}
And then inside openSidebar and closeSidebar I set sidebarOpen.
I also no longer use toggleClick. Instead I'm using:
$(document).on('click', '.toggle-box', toggleSidebar)
.on('click', '.list li', closeSidebar);
You could keep track of the sidebar state (open or close) using a class on the sidebar wrapper ("close" or "open"), and then use this class to determine in your click listener if you have to call closeSidebar or openSidebar.

jQuery toggle class and change it on click

I have the following code in my JS file:
jQuery("document").ready(function (e) {
var menu = e(".menu-container");
var button = e(".menu-functions");
e(window).scroll(function () {
if (e(this)
.scrollTop() > 150) {
menu.addClass("f-nav");
button.addClass("collapse-expand");
button.addClass('collapse');
} else {
menu.removeClass("f-nav");
button.removeClass("collapse");
button.removeClass("expand");
button.removeClass("collapse-expand");
}
});
//problem area
$('#menu-functions').click(function(){
if(button.hasClass('collapse'))
{
button.addClass('expand');
button.removeClass('collapse');
}
if(button.hasClass('expand'))
{
button.addClass('collapse');
button.removeClass('expand');
}
});
});
Now I need to make it so that the part under the // problem area starts to work. I reckon there's a toggleClass in jQuery, right? Some advanced conditions could do the trick, however I'm still learning and I need some help. I also need to find a way to animate() the .menu-container div whether the button state is expand or collapse:
If the button was clicked while it had the expand class
animate the menu from bottom to top with 98px;
If the button was clicked while it had the collapse class
animate the menu from top to bottom with 98px.
EDIT - JSFIDDLE:
jsfiddle.net/rcdhnh7L
Try it like this instead. Don't use e as the var for jQuery, that's just strange. And I simplified the problem area to directly grab the elements you want instead of iterating an existing collection.
jQuery("document").ready(function ($) {
var menu = $(".menu-container");
var button = $(".menu-functions");
$(window).scroll(function () {
if ($(this)
.scrollTop() > 150) {
menu.addClass("f-nav");
button.addClass("collapse-expand");
button.addClass('collapse');
} else {
menu.removeClass("f-nav");
button.removeClass("collapse");
button.removeClass("expand");
button.removeClass("collapse-expand");
}
});
//problem area
$('#menu-functions').click(function () {
$('.menu-functions.collapse').addClass('expand').removeClass('collapse');
$('.menu-functions.expand').addClass('collapse').removeClass('expand');
});
});
Or this should work as well:
//problem area
$('#menu-functions').click(function () {
$('.menu-functions.collapse, .menu-functions.expand').toggleClass('expand collapse');
});

How to close an open collapsed navbar when clicking outside of the navbar element in Bootstrap 3?

How can I close an open collapsed navbar on clicking outside of the navbar element? Currently, the only way to open or close it is by clicking on the navbar-toggle button.
See here for an example and code:
So far, I have tried the following which doesn't seem to work:
jQuery(document).click(function() {
});
jQuery('.navbar').click(function(event) {
jQuery(".navbar-collapse").collapse('hide');
event.stopPropagation();
});
Have a look that:
$(document).ready(function () {
$(document).click(function (event) {
var clickover = $(event.target);
var _opened = $(".navbar-collapse").hasClass("navbar-collapse in");
if (_opened === true && !clickover.hasClass("navbar-toggle")) {
$("button.navbar-toggle").click();
}
});
});
Your fiddle works with that: http://jsfiddle.net/52VtD/5718/
Its a modified version of this answer, which lacks the animation and is also a tiny bit more complicated.
I know, invoking the click() isn't very elegant, but collapse('hide') did not work for me either, and i think the animation is a bit nicer than adding and removing the classes hardly.
The accepted answer doesn't appear to work correctly. It only needs to check if "navbar-collapse" has the "in" class. We can then fire the collapse method as expected by using our reference to the navbar.
$(document).click(function (event) {
var clickover = $(event.target);
var $navbar = $(".navbar-collapse");
var _opened = $navbar.hasClass("in");
if (_opened === true && !clickover.hasClass("navbar-toggle")) {
$navbar.collapse('hide');
}
});
Using this works for me.
$(function() {
$(document).click(function (event) {
$('.navbar-collapse').collapse('hide');
});
});
The solution I decided to use was taken from the accepted answer here and from this answer
jQuery('body').bind('click', function(e) {
if(jQuery(e.target).closest('.navbar').length == 0) {
// click happened outside of .navbar, so hide
var opened = jQuery('.navbar-collapse').hasClass('collapse in');
if ( opened === true ) {
jQuery('.navbar-collapse').collapse('hide');
}
}
});
This hides an opened collapsed nav menu if the user clicks anywhere outside of the .navbar element. Of course clicking on .navbar-toggle still works to close the menu too.
Converted nozzleman's answer for Bootstrap 4(.3.1):
$(document).ready(function () {
$(document).click(
function (event) {
var target = $(event.target);
var _mobileMenuOpen = $(".navbar-collapse").hasClass("show");
if (_mobileMenuOpen === true && !target.hasClass("navbar-toggler")) {
$("button.navbar-toggler").click();
}
}
);
});
Placed in the ngOnInit().
When the document is loaded, this code waits for click events. If the mobile menu dropdown is open (i.e. the collapsible part of the navbar has the "show" class) and the clicked object (target) is not the mobile menu button (i.e. does not have the "navbar-toggler" class), then we tell the mobile menu button it has been clicked, and the menu closes.
stopPropagation() is not always the best solution. Rather use something like:
jQuery(document.body).on('click', function(ev){
if(jQuery(ev.target).closest('.navbar-collapse').length) return; // Not return false
// Hide navbar
});
I think it's dangerous to assume that you never want to listen to any other event from the .navbar. Which is impossible if you use stopPropagation().
I had a scenario where I had plain text and I didn't want the panel to close if a user clicks on the plain text on accident. The other answers here will close the panel even if you click on the text of an item that isn't a link.
To fix this I added on to Paul Tarr's answer by wrapping the solution in a check to see whether or not the click occurred anywhere inside:
if ($(event.target).parents(".navbar-collapse").length < 1) { }
The full code would become:
$(document).click(function (event) {
if ($(event.target).parents(".navbar-collapse").length < 1) {
var clickover = $(event.target);
var $navbar = $(".navbar-collapse");
var _opened = $navbar.hasClass("in");
if (_opened === true && !clickover.hasClass("navbar-toggle")) {
$navbar.collapse('hide');
}
}
});
In this demo fiddle you can see that if you click on a non-link inside of the panel it won't collapse it.
For latest Bootstrap, this is the correct answer.
$(document).click(function (event) {
var clickover = $(event.target);
var $navbar = $(".navbar-collapse");
var _opened = $navbar.hasClass("show");
if (_opened === true && !clickover.hasClass("navbar-toggler")) {
$navbar.collapse('hide');
}
});
It reads if .navbar-collapse has the word show in classes (which means menu is opened) and hides the navbar when you click/tap anywhere.
I've added a condition to #nozzleman's answer to check if the tap or click has been made on any element within the menu, and if that's the case, not to collapse it.
$(document).ready(function () {
$(document).click(function (event) {
var clickover = $(event.target);
var _opened = $(".navbar-collapse").hasClass("navbar-collapse in");
if (_opened === true && !clickover.hasClass("navbar-toggle") && clickover.parents('.navbar-collapse').length == 0) {
$("button.navbar-toggle").click();
}
});
});
The following code works for me and the advantage is that on small screens, it does not hide the .collapse when you click on its nav parent with .navbar .navbar-expand classes:
$(document).click(function (e) {
if($('.collapse').hasClass('show') && !$('nav').is(e.target) && $('nav').has(e.target).length === 0){
$('.navbar-toggler').click()
}
})
Vanilla Javascript.
Working on Bootstrap 5.2.
window.onload = function () {
document.addEventListener("click", function (event) {
// if the clicked element isn't child of the navbar, you must close it if is open
if (!event.target.closest("#navbar_id") && document.getElementById("navbarSupportedContent").classList.contains("show")) {
document.getElementById("hamburger_menu_button").click();
}
});
}
https://jsfiddle.net/j4tgpbxz/
You just need to add an id to the navbar element, and then check if the clicked element is a child of that same navbar and the content you want to hide (dropdown) is being shown.
For Bootstrap 4
Bootstrap 4 doesn't have an in class. This is Coffeescript.
$(document).click (e)->
#console.log e.target
unless $('#toggle-button').has(e.target).length || $('#toggle-menu').has(e.target).length
$('#toggle-menu').collapse('hide')
So basically, unless you click the button or the menu, close the menu.
Note: Strange, on iOS clicking on text doesn't register a click event, nor a mouseup event. Clicking on an image does fire events though.
For Bootstrap 4:
$(document).click(function(event) {
$(event.target).closest(".navbar").length || $(".navbar-collapse.show").length && $(".navbar-collapse.show").collapse("hide")
});
$(document).click(function (event) {
if ($('.navbar-collapse').attr('aria-expanded') == "true") {
$('.navbar-collapse:visible').click();
}
});
$(window).click(function (e) {
if ($(e.target).closest('.codehim-dropdown').length) {
return;
}
if ($(e.target).closest(offCanvas).length) {
return;
}
//check if menu really opened
if ($(hamburger).hasClass("active")) {
closeMenu();
}
$(dimOverlay).fadeOut();
$(".menu-items").slideUp();
$(".dropdown-heading").removeClass("active");
});
I had some problems with some answers here, and I would like to also be able to close the expanded menu on demand. So I did it with a simple function, and simulating the click.
function closeMenu(){
element = document.getElementById('nav_top');
if(element){
if(element.classList.contains('show')){
document.getElementById('navbar_toggler').dispatchEvent(new CustomEvent('click'));
}
}
}
$(document).ready(function () {
$(document).click(function (event) {
closeMenu();
});
});
Using this method you can close it when clicked outside, but also you can call the closeMenu() at any time from any other function.
I know its quite awhile for the answer. But I think the answer here could helps.
Lets say the condition: if user want to close the navbar when click outside but not when user click any element inside of the navbar
use the event.target and target the element's closest classname whether its has the navbar class or not. If yes which means user is clicking element inside of the navbar and not to close the navbar.
$(function() {
$(document).click(function (event) {
var clickover = $(event.target);
var _opened = $(".navbar-collapse").hasClass("navbar-collapse collapse show");
if (_opened === true && clickover.closest('.navbar').length === 0) {
$(".navbar-collapse").collapse('hide');
}
});
});

Categories

Resources