JS menu issue with preventDefault who close my menu - javascript

it is my first question on Stackoverflow after many years of reading answers here. Sorry for my english, it is not my nativelanguage.
I develop on wordpress a system to open and close the menu and open the submenu.
When I open the submenu my menu closes despite I prevent the click on a tag
let openMenu = document.querySelectorAll('.et_mobile_menu .menu-item-has-children>a');
let arrayLinkMenu = Array.from(openMenu);
for(let i = 0; i < arrayLinkMenu.length; i++){
arrayLinkMenu[i].addEventListener('click', (event) => {
arrayLinkMenu[i].nextElementSibling.style.setProperty('display', 'block', 'important');
event.preventDefault();
event.stopPropagation();
})
}
I tried with return false but I get the same issue.
When I click, it creates an a tag with # as URL. It's like this my page refresh but not... I never see my web browser refresh really my page.
I put the code who open and close the menu, we never know
/**If menu is open create div with button close menu and add interation to submenu*/
//Verify the click on the button
let buttonMenu = document.getElementsByClassName('mobile_nav');
buttonMenu[0].addEventListener('click', function(){
let menuClosed = document.getElementsByClassName('closed-menu');
if (menuClosed.length > 0){
menuClosed[0].remove();
}
//if it' open create div or a tag
if(!buttonMenu[0].classList.contains('opened')){
let aTag = document.createElement('a');
aTag.href = '#';
aTag.innerHTML = '<img src="url_image" />';
aTag.classList.add('closed-menu')
let mobileMenu = document.getElementsByClassName('et_mobile_menu');
mobileMenu[0].appendChild(aTag);
//create action to close menu
let menuClosed = document.getElementsByClassName('closed-menu');
if(menuClosed.length > 0){
let mobileNav = document.getElementsByClassName('mobile_nav')
menuClosed[0].addEventListener('click', function(event){
mobileNav[0].classList.remove('opened');
mobileNav[0].classList.add('closed');
event.preventDefault();
})
}
//click on menu with subMenu
let openMenu = document.querySelectorAll('.et_mobile_menu .menu-item-has-children>a');
let arrayLinkMenu = Array.from(openMenu);
for(let i = 0; i < arrayLinkMenu.length; i++){
arrayLinkMenu[i].addEventListener('click', (event) => {
arrayLinkMenu[i].nextElementSibling.style.setProperty('display', 'block', 'important');
event.preventDefault();
event.stopPropagation();
return false;
})
}
}else{
// take an ellement and remove it to not have many ellements on same menu
let menuClosed = document.getElementsByClassName('closed-menu');
if (menuClosed.length > 0){
menuClosed[0].remove();
}
}
})
Thanks per advance.

Try to stopImmediatePropagation() so you are sure that not even other event listeners registered on the element itself are executed.

Related

Getting wordpress menu to open submenu on click on the main menu item

I've looked at many of the answers on this website but none of them are working on my website
I have the mobile version working with a workaround code
window.addEventListener('load', function(){
var menuItems = document.getElementsByClassName("menu-item-has-children");
/*
* Bij aanpassing mobiel menu, console.log(menuItems);
* aanzetten, controleer de indexen van de mobiele menu items
*/
// console.log(menuItems);
menuItems[5].firstChild.removeAttribute("href");
menuItems[5].firstChild.setAttribute("href", "#");
menuItems[5].firstChild.addEventListener('click', (event) => {
menuItems[5].firstChild.lastChild.click();
});
menuItems[6].firstChild.removeAttribute("href");
menuItems[6].firstChild.setAttribute("href", "#");
menuItems[6].firstChild.addEventListener('click', (event) => {
menuItems[6].firstChild.lastChild.click();
});
menuItems[7].firstChild.removeAttribute("href");
menuItems[7].firstChild.setAttribute("href", "#");
menuItems[7].firstChild.addEventListener('click', (event) => {
menuItems[7].firstChild.lastChild.click();
});
menuItems[8].firstChild.removeAttribute("href");
menuItems[8].firstChild.setAttribute("href", "#");
menuItems[8].firstChild.addEventListener('click', (event) => {
menuItems[8].firstChild.lastChild.click();
});
menuItems[9].firstChild.removeAttribute("href");
menuItems[9].firstChild.setAttribute("href", "#");
menuItems[9].firstChild.addEventListener('click', (event) => {
menuItems[9].firstChild.lastChild.click();
});
});
But I want the desktop version to work the same way. The hover function can go if it's in the way.
I've tried this code, but it doesn't do the trick.
if(clicked == false){
document.getElementById("menu-item-has-children").style.display = "none";
clicked = true;
}else if (clicked == true){
document.getElementById("menu-item-has-children").style.display = "block";
clicked = false;
}
The Satelite them is a real ##$ if it comes to the codes. I've looked and looked, but I can't find the code that works the hover anywhere (probably tucked away in a file I'll never find). But I'm using a child theme anyway, so I can add .php an .js files to overwrite anything. I just haven't found anything that works. Does anyone have any idea of how I could get this on click show of the sub menu to work?

How can I get an EventListener on a Select dropdown using a loop to work as expected

I have some HTML tabs which use radio buttons to control them. However I am using a select drop down menu with some javascript to control them on mobile screen sizes.
// Get select element for mobile navigation
const select = document.getElementById("location");
// Event listener for selecting tabs event for mobile
select.addEventListener("change", (e) => {
const target = e.target.value;
const venueTabs = document.querySelectorAll(".tabs__radio");
for (let i = 0; i < venueTabs.length; i++) {
if (venueTabs[i].id === target) {
venueTabs[i].setAttribute("checked", "checked");
console.log(venueTabs[i], target);
} else if (venueTabs[i].id !== target) {
venueTabs[i].removeAttribute("checked");
}
}
});
My eventListener seems to work and is logging out what is expected. It compares the tab div id to the event target.
However this only seems to work when I test each select option twice, on the 3rd attempt the tabbed content disappears (css switches to display: none).
I can't seem to work out what is causing the error.
I have set up a code sandbox with my code https://codesandbox.io/s/nice-ramanujan-2yq1r?file=/src/index.js to help debug it. If the drop down menus isn't showing, you may have to view it for mobile/ below 700px wide & it'll display the select drop down menu.
Can anyone help identify what is causing this bug? I previously had hard coded the EventListener that worked perfectly, it looked like this
select.addEventListener("change", (e) => {
const target = e.target;
const tabone = document.getElementById("tab0");
const tabtwo = document.getElementById("tab1");
const tabthree = document.getElementById("tab2");
const tabfour = document.getElementById("tab3");
if (target.value === "tab0") {
tabtwo.removeAttribute("checked");
tabthree.removeAttribute("checked");
tabfour.removeAttribute("checked");
tabone.setAttribute("checked", "checked");
} else if (target.value === "tab1") {
tabthree.removeAttribute("checked");
tabfour.removeAttribute("checked");
tabone.removeAttribute("checked");
tabtwo.setAttribute("checked", "checked");
} else if (target.value === "tab2") {
tabfour.removeAttribute("checked");
tabone.removeAttribute("checked");
tabtwo.removeAttribute("checked");
tabthree.setAttribute("checked", "checked");
} else if (target.value === "tab3") {
tabone.removeAttribute("checked");
tabtwo.removeAttribute("checked");
tabthree.removeAttribute("checked");
tabfour.setAttribute("checked", "checked");
}
});
However it's not dynamic enough to take any number of tabs that may exist.
This doesn't need any looping over all the radio buttons to begin with - just select the one element you want to set checked via its id:
select.addEventListener("change", (e) => {
const target = e.target.value;
const venueTab = document.querySelector("#"+target);
venueTab.checked = true;
});

Close drop down menu when clicking outside menu

I have the following
function subNavToggle() {
var subNav = document.getElementById("subnav-section");
if (subNav.className === "navigation-subnav") {
subNav.className += " responsive";
} else {
subNav.className = "navigation-subnav";
}
}
I am trying to get the expanded menu to close when clicking outside of menu.
I have this, which will close the menu, but it also closes the hamburger menu - preventing the user to be able to open again.
$(document).click(function(event) {
var $target = $(event.target);
if(!$target.closest('.sub_nav_links').length &&
$('.sub_nav_links').is(":visible")) {
$('.sub_nav_links').hide();
}
});
Also thought I could get away with the following, but it actually does the opposite. Opening outside menu item.
window.onclick = subNav;
$('html').on('click, touchend', function (e) {
// Close hamburger menu when tapping outside
if ($(e.target).closest('#subnav-section').length == 0) {
var opened = $('.navigation-subnav').hasClass('responsive');
if (opened === true) {
$('.navigation-subnav').collapse('hide');
}
}
});
// to hide
$(document).click(function(){
$("#submenu").hide();
});
// you could possibly prevent to hide menu while using navigation
$("#menu").click(function(e){
e.stopPropagation();
});

Removing a tab from tabPanel

var tabPanel = Ext.getCmp('tabPanel');
for(var i=1; i<tabPanel.items.length; i++)
{
tabPanel.items.removeAt(i);
i--;
}
tabPanel.doLayout();
I'm trying to remove all the tabs (except the first one) from the tabPanel.
This code is doing that. I checked it using firebug.
But still, it is not reflecting in the UI.
Isn't doLayout() enough?
Instead of calling
tabPanel.items.removeAt(i);
Call
tabPanel.remove(tabPanel.items.getAt(i));
Then you're telling the container instead of the mixed collection to remove the tab
Another way to do it is
tabPanel.removeChildEls(function(tab){
return tab != tabPanel.items.first();
});
This closes a tab by clicking the middle button of your mouse.
var middleClick = $(document).mousedown(function(e) {
if(e.which == 2){
var tabPanel = <%= tabPanel.ClientID %>;
var activeTab = tabPanel.getActiveTab();
if (e.target.textContent == activeTab.title) {
var activeTabIndex = tabPanel.items.findIndex('id', activeTab.id);
tabPanel.remove(activeTabIndex);
}
}
return true;
});
Hope it helps!! =)

In JavaScript e.target is not working as I expected

I have written some JavaScript that opens an element when an element is clicked. However I can't get the:
var menu = document.getElementById(show);
if (menuOpen && e.target !== menu){...}
This is not working to how I want it because:
You can open more than one of the showed elements when I only want one open at a time.
When I click inside the element it closes, I only want it to close if they have clicked outside the box.
function openBox(button, show){
var menuOpen = false; //to toggle when the button is clicked.
// checks the whole document for clicks and then if the element is open it will >
// check to see if you have clicked away from it or not.
document.addEventListener("click", function(e){
var menu = document.getElementById(show);
if (menuOpen && e.target !== menu){ // if elements open and the click event target does not match >
menu.style.display = "none"; // we will close it
menuOpen = false;
}
},false);
// add an event listner to the button element and then if its clicked stop any >
// links an stop bubbling and then change the display style.
document.getElementById(button).addEventListener("click", function(e){
var menu = document.getElementById(show);
e.preventDefault();
e.stopPropagation();
if (menuOpen){
menu.style.display = "none";
menuOpen = false;
} else {
menu.style.display = "block";
menuOpen = true;
}
},false);
}
openBox("signInButton", "signIn");
openBox("bagButton", "shoppingBag");
openBox("currencyButton", "currencySelect");
http://jsfiddle.net/jamcoupe/9CEGw/
Edit:
After #Felix Kling post I changed the code to:
document.addEventListener("click", function(e){
var menu = document.getElementById(show);
if (menuOpen && (e.target.parentNode !== menu) && (e.target !== menu)){
menu.className = "closedBoxes";
pointer = document.getElementById(arrow).className = "arrowE";
menuOpen = false;
}
},false);
This has solve the first problem but I am still stuck on how to make it so that only one box is ever open at one giving time. So when a user has signIn box open and clicks on currencyChanger I want the signIn box to be off.
http://jsfiddle.net/jamcoupe/kcF9Z/7/
When I click inside the element it closes, I only want it to close if they have clicked outside the box.
As I already said in my comment, if the box contains other elements, then e.target does not refer to the box itself but to the element within the box.
So in order to test whether the click was outside or not, you have to test whether e.target is an element within the box or the box itself. For that, you have to traverse the DOM tree.
Example:
var target = e.target;
while(target && target !== menu) {
target = target.parentNode;
}
if(!target) {
// click was outside of the box
}
You can open more than one of the showed elements when I only want one open at a time.
If you want to make the three dialogs dependent on each other, you have to maintain some shared state. I'd suggest, instead of having three dialogs, you can have one dialog manager which takes care of opening and closing the boxes.
Example:
function DialogManager() {
this.dialogs_ = {};
this.openedDialog_ = null;
this.init_();
}
DialogManager.prototype.init_ = function(e) {
var self = this;
document.addEventListener('click', function(e) {
var id = e.target.id;
if(id && id in self.dialogs_) { // if one of the buttons was clicked.
self.openDialog(id); // the dialog is opened (or closed)
return;
}
if(self.openedDialog_) { // if a dialog is currently open, we have to
var target = e.target; // close it if the click was outside
while(target && target.id !== self.openedDialog_) {
target = target.parentNode;
}
if(!target) {
self.closeDialog(self.openedDialog_);
}
}
}, false);
};
DialogManager.prototype.registerDialog = function(button_id, dialog_id) {
this.dialogs_[button_id] = dialog_id;
};
DialogManager.prototype.openDialog = function(id) {
var open_id = this.openedDialog_;
if(open_id) {
this.closeDialog(open_id);
}
if(id !== open_id) {
var dialog = document.getElementById(this.dialogs_[id]);
dialog.style.display = "block";
this.openedDialog_ = id;
}
};
DialogManager.prototype.closeDialog = function(id) {
var dialog = document.getElementById(this.dialogs_[id]);
dialog.style.display = "none";
this.openedDialog_ = null;
};
DEMO
I hope this gives you some idea. There is still a lot which can be improved, for example, now the manager listens to every click event, no matter whether a dialog is open or not.

Categories