I am building a responsive mobile menu. I am a beginner so don't know how to use loops effectively.
The Problem is that When in mobile view, hamburger menu icon shows and when it is clicked, it changes to close menu icon & when clicked again, changes to hamburger menu.
BUT it stucks there. it only works to 2 clicks and after that it stuck to hamburger menu icon & never changes to close menu icon.
JAVASCRIPT CODE:
window.addEventListener('resize', function detectWidth(){
let screenWidth = screen.width;
if(screenWidth <= 800){
document.querySelector("nav ul").innerHTML = `<img id="menuIcon" src="Header/menuIcon.png" alt="Menu Icon">`;
// TO SHOW MENU ITEMS & CLOSE MENU ICON AFTER CLICKING ON HAMBURGER MENU BUTTON
document.querySelector("#menuIcon").addEventListener("click", function(){
document.querySelector("#menuIcon").outerHTML = `<img id="closMenuIcon" src="Header/closeMenuIcon.png" alt="Close Menu Icon">`;
//TO CHANGE BACK TO MENU ICON
document.querySelector("#closMenuIcon").addEventListener("click", function () {
document.querySelector("#closMenuIcon").outerHTML = `<img id="menuIcon" src="Header/menuIcon.png" alt="Menu Icon">`;
});
})
} else{
document.querySelector("nav ul").innerHTML = `<ul>
<li>Home</li>
<li>Shop</li>
<li>About us</li>
<li>Contact us</li>
</ul>`;
}
});
please forgive me if it is so obvious, I am a beginner and i think it requires loop of some kind.
Even though It's better to use toggling css className, I want to point out on the problem in this case. In your case scenario, you apply event on button element but the thing is outerHTML replaces the element so all events get fired. If you want to stick out to your method, you need to redeclare the events one more time.
I found the answer myself. I really don't know how it works but yeah, at least it works now.
window.addEventListener('resize', function detectWidth(){
let screenWidth = screen.width;
if(screenWidth <= 800){
document.querySelector("nav ul").innerHTML = `<img id="menuIcon" src="Header/menuIcon.png" alt="Menu Icon">`;
// TO SHOW MENU ITEMS & CLOSE MENU ICON AFTER CLICKING ON HAMBURGER MENU BUTTON
function toggleMenu(){
document.querySelector("#menuIcon").addEventListener("click", function(){
document.querySelector("#menuIcon").outerHTML = `<img id="closMenuIcon" src="Header/closeMenuIcon.png" alt="Close Menu Icon">`;
//TO CHANGE BACK TO MENU ICON
document.querySelector("#closMenuIcon").addEventListener("click", function () {
document.querySelector("#closMenuIcon").outerHTML = `<img id="menuIcon" src="Header/menuIcon.png" alt="Menu Icon">`;
toggleMenu();
});
})
}
toggleMenu();
} else{
document.querySelector("nav ul").innerHTML = `<ul>
<li>Home</li>
<li>Shop</li>
<li>About us</li>
<li>Contact us</li>
</ul>`;
}
});
Related
I am creating a web app that searches for events using an event api. I have a filter navbar where the user can enter certain filters (date-range, event category, distance, etc). I put a click handler on one of the navbar elements(category) so that it displays the hidden dropdown menu upon click. If the same navbar element is clicked again or any of its children (hidden dropdown elements), the dropdown menu should disappear. I used jQuery to change the text of the navbar element to the text of the category that was clicked from the dropdown menu. However, when I try to click the navbar element again, it is locked and I can't open it. I can't seem to find what is wrong with my code. Hopefully some additional eyes can help me spot it.
Here is the code.
<nav class="filter__container">
<ul class="filter">
<li class="filter__category">Category
<div class="filter__category__choices">
<p class="filter__category__choice">Art</p>
<p class="filter__category__choice">Music</p>
<p class="filter__category__choice">Sports</p>
<p class="filter__category__choice">Festival</p>
<p class="filter__category__choice">Miscellaneous</p>
</div>
</li>
<li class="filter__submit">Apply Filters</li>
</ul>
</nav>
const categoryFilter = $(".filter__category");
let categoryOpen = false;
categoryFilter.click((e) => {
if(e.target !== categoryFilter[0]) {
$(".filter__category").text($(e.target).text());
}
if(categoryOpen) {
categoryPopup.slideUp();
categoryOpen = false;
}
else {
categoryPopup.slideDown();
categoryOpen = true;
}
});
I bought this theme a while back and have been chopping it up and modifying it to add/remove functionality. There is this slidein menu that appears on the page once a link is clicked from the navbar menu. The issue is that there is an X button to close the menu that is supposed to toggle/remove a class from the #btn-offcanvas-menu element when it is clicked (#btn-close-canvasmenu is clickable element); it works on the desktop but not the responsive mobile site. The only way it is toggled/removed on mobile is if the original link is clicked again. I have looked at the below questions here, and several others, including trying to use the closest/find options but nothing seems to work. What am I missing?
Desired behavior: the isLeft class should toggle/be removed when the #btn-close-canvasmenu link is clicked. It is on desktop but not mobile.
Javascript not working on mobile but works on desktop.
JavaScript - removeClass not working?
ToggleClass and RemoveClass not working
JQuery - ToggleClass/AddClass/RemoveClass
How to toggle class of closest element jquery toggle class on closest span
This is relevant portion of the index page...
<li id="recent-mobile"><!-- this is hidden by CSS on desktop -->
<a id="btn-offcanvas-menu" href="#">Recent Results</a>
</li>
<li id="recent-results"><!-- this is hidden by CSS on mobile -->
<div class="header-buttons pull-right hidden-xs hidden-sm">
<div class="navright-button">
<i class="fa fa-bars"> Recent Results</i>
</div>
</div>
</li>
<!-- Menu OffCanvas right begin -->
<div class="navright-button">
<div class="compact-menu-canvas" id="offcanvas-menu">
<h3>menu</h3><a id="btn-close-canvasmenu"><i class="fa fa-close"></i></a>
<nav>
<ul class="clearfix">
<li>Home</li>
<li>Features</li>
<li>Pages</li>
<li>Portfolios</li>
<li>Shop</li>
<li>Blog</li>
<li>Contact Us</li>
</ul>
</nav>
</div>
</div>
<!-- Menu OffCanvas right close -->
This is the relevant portion of the javascript compact.js file...
$("#btn-close-canvasmenu").on("click", function() {
$("#offcanvas-menu").stop().animate({
right: "-260px"
}, 300), $("a#btn-offcanvas-menu").removeClass("isLeft")
});
$(document).on("click", "#btn-offcanvas-menu, #btn-offcanvas-menu-mobile", {} , function(a){
var id = $(this).attr('id');
if (id === "btn-offcanvas-menu-mobile") {
$("#btn-close-canvasmenu").toggleClass("mobile");
}
return a.preventDefault(), $(this).hasClass("isLeft") ? $("#offcanvas-menu").stop().animate({
right: "-260px"
}, 300) : $("#offcanvas-menu").stop().animate({
right: "0px"
}, 300), $(this).toggleClass("isLeft"), false
});
EDIT (fixed 2/16/20): I edited the js file file to reflect this updated function: $("#btn-close-canvasmenu").on("click", function()
Essentially, what fixed it was changing the selector from #btn-offcanvas-menu to a#btn-offcanvas-menu. Not sure why that worked as opposed to using closest/find method but once I did, it toggled/removed the class on both desktop and mobile correctly. If anyone has anything thoughts on why the a made the difference with the selector, I'd appreciate the feedback as I am not an expert on js/jQuery. Otherwise, this can be considered closed.
Changing the selector in the compact.js file from #btn-offcanvas-menu to a#btn-offcanvas-menu fixed the issue and while this worked, it was the wrong way to correct the issue as connexo pointed out due to the duplicate ids.
The correct way to resolve this was to change the mobile navbar itself so I could use an id specifically for the mobile that only appeared there.
<nav id="mobile-menu" class="site-mobile-menu hidden-lg hidden-md">
<ul>
<li id="recent-mobile">
Recent Results
</li>
</ul>
</nav>
Next I changed the js function that populated the html for the mobile menu to use prepend instead of append so it populated everything above the Recent Results link...
$("#desktop-menu > ul").children().clone().prependTo($("#mobile-menu > ul")), $("#show-mobile-menu").on("click", function() {
$(this).toggleClass("clicked"), $("#mobile-menu > ul").stop(true, true).slideToggle()
});
Then I tweaked the js function to toggle the class to mobile for the #btn-close-canvasmenu if the selector was #btn-offcanvas-menu-mobile to be used later...
$(document).on("click","#btn-offcanvas-menu,#btn-offcanvas-menu-mobile", {} , function(a){
var id = $(this).attr('id');
if (id === "btn-offcanvas-menu-mobile") {
$("#btn-close-canvasmenu").toggleClass("mobile");
}
return a.preventDefault(), $(this).hasClass("isLeft") ? $("#offcanvas-menu").stop().animate({
right: "-260px"
}, 300) : $("#offcanvas-menu").stop().animate({
right: "0px"
}, 300), $(this).toggleClass("isLeft"), false
});
Finally, I tweaked the js function that closed the menu to check the class to determine which id to toggle the isLeft class for...
$(document).on("click","#btn-close-canvasmenu", {} , function(a){
var id = $(this).attr('id');
if ($(this).hasClass("mobile")) {
var container = $("#btn-offcanvas-menu-mobile");
$("#btn-close-canvasmenu").toggleClass("mobile");
} else {
var container = $("#btn-offcanvas-menu");
}
$("#offcanvas-menu").stop().animate({
right: "-260px"
}, 300), container.removeClass("isLeft")
});
I want to have my menu closed when the user clicks outside the menu, not only outside the navbar element. Because I have more collapses in my menu, this solution did not work for me: How to close an open collapsed navbar when clicking outside of the navbar element in Bootstrap 3?
The menu disapeares when I click outside the menu, but when I click on the link with a dropdown, the whole menu collapses.
<div class="collapse navbar-collapse nav-mobile" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="list-group panel">
Webshop
<ul class="collapse" id="submenu-1">
Industriƫle verpakkingen
Promotionele verpakkingen
Gelamineerde verpakkingen
Enveloppen &verzend verpakkingen
Medische verpakkingen
Co-packing
</ul>
</li>
</ul>
You can use this to collapse if not clicking a link: fiddle
$(document).click(function(e) {
if (!$(e.target).is('a')) {
$('.collapse').collapse('hide');
}
});
another alternative, you can add code below :
<script>
$(document).ready(function(){
$(".list-group ").hover(
function() {
$('.collapse', this).stop( true, true ).slideDown("fast");
$(this).toggleClass('open');
},
function() {
$('.collapse', this).stop( true, true ).slideUp("fast");
$(this).toggleClass('open');
}
);
});
</script>
another example : dtc-eng
Here is my take on this:
$(document).on('click', function(event){
var $clickedOn = $(event.target),
$collapsableItems = $('.collapse'),
isToggleButton = ($clickedOn.closest('.navbar-toggle').length == 1),
isLink = ($clickedOn.closest('a').length == 1),
isOutsideNavbar = ($clickedOn.parents('.navbar').length == 0);
if( (!isToggleButton && isLink) || isOutsideNavbar ) {
$collapsableItems.each(function(){
$(this).collapse('hide');
});
}
});
This solution handles:
single page website/applications (and will work on multi-pages too).
clicks on:
.navbar-toggle elements (could be <buttons> or <a>, and it handles clicks on potential inner elements like <span> or <strong> or whatever).
on simple <a> elements (again, it handles clicks on inner elements).
just outside some particular parent (ie. .navbar).
multiple collapsable (.collapse) elements that might be open (indistinct to where they are placed in the DOM).
Not enough for you? No problem. You can customize most of the selectors passed to jQuery (document, .collapse, .navbar, etc) to suit your needs or even add more conditions.
Problem
I have a dropdown menu that toggles between a hamburger menu and a cross icon when the navigation opens and closes. However, if a user opens the menu, then resizes the window and the window width is still less than 768px (still open), it shows both the icons stacked on top of each other when it only should show the cross.
On a side note, I'm looking to just simplify the complexity of this Javascript snippet. I'm not sure that adding and removing a class of is-visible was the correct/best approach.
JSFiddle: https://jsfiddle.net/bdmebsu8/
scripts.js
$(function(){
// Window size
if ($(window).width() <= 768) {
$(".icon-cross").hide();
$(".icon-menu").addClass("is-visible");
$(".icon-menu").show();
} else {
$(".icon-menu").hide();
$(".icon-menu").removeClass("is-visible");
}
$(window).resize(function(){
var w = $(this).innerWidth();
if (w > 768) {
$(".nav__list--dropdown").hide();
$(".icon-cross").hide();
$(".icon-menu").hide();
$(".icon-cross").removeClass("is-visible");
$(".icon-menu").removeClass("is-visible");
} else {
$(".icon-cross").hide();
$(".icon-menu").show();
$(".icon-menu").addClass("is-visible");
}
});
// Dropdown menu
$(".nav__menu").on("click", function(){
$(".is-hidden").slideToggle("slow");
var menuVisible = $(".icon-menu").hasClass("is-visible")
if (menuVisible) {
$(".icon-menu").removeClass("is-visible");
$(".icon-menu").hide();
$(".icon-cross").addClass("is-visible");
$(".icon-cross").show();
} else {
$(".icon-cross").removeClass("is-visible");
$(".icon-cross").hide();
$(".icon-menu").addClass("is-visible");
$(".icon-menu").show();
}
});
});
index.html
<div class="dropdown">
<ul class="nav__list--dropdown is-hidden">
<li class="item--services--dropdown">Services</li>
<li class="item--projects--dropdown">Projects</li>
<li class="item--teaching--dropdown">Teaching</li>
<li class="item--blog--dropdown">Blog</li>
<li class="item--contact--dropdown">Contact</li>
</ul>
</div>
<div class="nav__menu">
<img src="src/img/sm-menu.png" class="icon-menu" alt="Open Menu">
<img src="src/img/cross-dark.png" class="icon-cross" alt="Close Menu">
</div>
What you could do to simplify your script:
$(function(){
function updateMenu(){
// all logic in here for checking width and show/hide/set classes
}
updateMenu(); // runs on doc ready
$(window).on("resize", updateMenu);
}
I have a burger icon that when clicked turns into an X. When clicked again turns back into the 3 lines. I have it working so when the links are clicked the menu goes away, but the burger menu doesn't return back to 3 lines. Nothing I have tried is working. Here is what I have.
var burgerIcon = $('.burger-icon');
function toggleBurger(){
burgerIcon.click(function(){
if(burgerIcon.hasClass("is-active") === true)
{
burgerIcon.removeClass("is-active");
//console.log("remove");
}
else
{
burgerIcon.addClass("is-active");
//console.log("add");
}
});
}
toggleBurger();
$('.toggle-nav').click(function() {
$('body').toggleClass('show-nav');
return false;
});
$('nav ul li > a').click(function(){
//console.log("clicked");;
$('body').trigger( "click" );
burgerIcon.trigger( "click" );
});
HTML:
<nav>
<ul data-magellan-expedition="fixed">
<li data-magellan-arrival="work">
Work
</li>
<li data-magellan-arrival="about">
About
</li>
<li data-magellan-arrival="shadow">
Shadow CC
</li>
<li data-magellan-arrival="clients">
Clients
</li>
</ul>
</nav>
Here is a fiddle of what I'm trying to explain: jsFiddle
Since you are using jQuery in your code you can leverage that and then really ALL you need I believe is this:
$('nav ul li > a,.c-hamburger').click(function () {
console.log("clicked");
$('body').toggleClass('show-nav');
if ($('body').hasClass('show-nav')) {
$('.c-hamburger').addClass("is-active");
} else {
$('.c-hamburger').removeClass("is-active");
}
});
Updated fiddle: http://jsfiddle.net/qe38m0t9/2/
NOTE: this uses two selectors, one for the "hamburger" thing and another for the menu separated by a comma then does the same thing depending upon which is clicked.