2

I'm trying to make Magento menu open categories only on click and disable hover function. It opens subcategories but once you open a subcategory it doesn't collapse and you can't expand a different subcategory

I added in app/design/frontend/Vendor/theme/require-config.js the following code

var config = {
 config: {
 mixins: {
 'mage/menu': {
 'Magento_Theme/js/menu-mixin': true
 }
 }
 },
};

Then, in app/design/frontend/Vendor/theme/Magento_Theme/web/js I've added the following script:

define([
 'jquery',
 ],
 function ($) {
 return function () {
 $.widget('mage.custommenu', $.mage.menu, {
 _toggleDesktopMode: function () {
 var html, subMenus;
 $(this.element).off('click mousedown mouseenter mouseleave');
 this._on({
 /**
 * Prevent focus from sticking to links inside menu after clicking
 * them (focus should always stay on UL during navigation).
 */
 'mousedown .ui-menu-item > a': function (event) {
 event.preventDefault();
 },
 /**
 * Prevent focus from sticking to links inside menu after clicking
 * them (focus should always stay on UL during navigation).
 */
 'click .ui-state-disabled > a': function (event) {
 event.preventDefault();
 },
 /**
 * @param {jQuer.Event} event
 */
 'click .ui-menu-item:has(a)': function (event) {
 var target = $(event.target).closest('.ui-menu-item');
 if (!this.mouseHandled && target.not('.ui-state-disabled').length) {
 this.select(event);
 // Only set the mouseHandled flag if the event will bubble, see #9469.
 if (!event.isPropagationStopped()) {
 this.mouseHandled = true;
 }
 // Open submenu on click
 if (target.has('.ui-menu').length) {
 this.expand(event);
 } else if ($(this.document[0].activeElement).closest('.ui-menu').length) {
 // Redirect focus to the menu
 this.element.trigger('focus', [true]);
 // If the active item is on the top level, let it stay active.
 // Otherwise, blur the active item since it is no longer visible.
 if (this.active && this.active.parents('.ui-menu').length === 1) { //eslint-disable-line
 clearTimeout(this.timer);
 }
 }
 }
 subMenus = this.element.find('.level-top');
 $.each(subMenus, $.proxy(function (index, item) {
 var category = $(item).find('> a span').not('.ui-menu-icon').text(),
 categoryUrl = $(item).find('> a').attr('href'),
 menu = $(item).find('> .ui-menu');
 this.categoryLink = $('<a>')
 .attr('href', categoryUrl)
 .text($.mage.__('%1').replace('%1', category));
 this.categoryParent = $('<li>')
 .addClass('ui-menu-item all-category')
 .html(this.categoryLink);
 if (menu.find('.all-category').length === 0) {
 menu.prepend(this.categoryParent);
 }
 }, this));
 },
 /**
 * @param {jQuery.Event} event
 */
 'click .ui-menu-item.parent': function (event) {
 var target = $(event.target).closest('.ui-menu-item');
 if ($(target).hasClass('parent')) {
 event.preventDefault();
 }
 var target = $(event.currentTarget),
 submenu = this.options.menus,
 ulElement,
 ulElementWidth,
 width,
 targetPageX,
 rightBound;
 if (target.has(submenu)) {
 ulElement = target.find(submenu);
 ulElementWidth = ulElement.outerWidth(true);
 width = target.outerWidth() * 2;
 targetPageX = target.offset().left;
 rightBound = $(window).width();
 if (ulElementWidth + width + targetPageX > rightBound) {
 ulElement.addClass('submenu-reverse');
 }
 if (targetPageX - ulElementWidth < 0) {
 ulElement.removeClass('submenu-reverse');
 }
 }
 // Remove ui-state-active class from siblings of the newly focused menu item
 // to avoid a jump caused by adjacent elements both having a class with a border
 target.siblings().children('.ui-state-active').removeClass('ui-state-active');
 this.focus(event, target);
 },
 /**
 * @param {jQuery.Event} event
 */
 'click .ui-menu-item': function (event) {
 var target = $(event.target).closest('.ui-menu-item');
 if ($(target).hasClass('level0')) {
 return;
 }
 var target = $(event.currentTarget),
 submenu = this.options.menus,
 ulElement,
 ulElementWidth,
 width,
 targetPageX,
 rightBound;
 if (target.has(submenu)) {
 ulElement = target.find(submenu);
 ulElementWidth = ulElement.outerWidth(true);
 width = target.outerWidth() * 2;
 targetPageX = target.offset().left;
 rightBound = $(window).width();
 if (ulElementWidth + width + targetPageX > rightBound) {
 ulElement.addClass('submenu-reverse');
 }
 if (targetPageX - ulElementWidth < 0) {
 ulElement.removeClass('submenu-reverse');
 }
 }
 // Remove ui-state-active class from siblings of the newly focused menu item
 // to avoid a jump caused by adjacent elements both having a class with a border
 target.siblings().children('.ui-state-active').removeClass('ui-state-active');
 this.focus(event, target);
 },
 });
 html = $('html');
 if (html.hasClass('nav-open')) {
 html.removeClass('nav-open');
 setTimeout(function () {
 html.removeClass('nav-before-open');
 }, this.options.hideDelay);
 }
 },
 focus: function () {
 return false;
 },
 });
 return $.mage.custommenu;
 }
 });

Finally, I've updated topmenu.phtml file in app/design/frontend/Vendor/theme/Magento_Theme/templates/html/topmenu.phtml

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
/**
 * Top menu for store
 *
 * @var $block \Magento\Theme\Block\Html\Topmenu
 */
$columnsLimit = $block->getColumnsLimit() ?: 0;
$_menuHtml = $block->getHtml('level-top', 'submenu', $columnsLimit)
?>
<nav class="navigation" data-action="navigation">
 <ul data-mage-init='{"menu":{"responsive":true, "expanded":true, "position":{"my":"left top","at":"left bottom"}}}'>
 <?= /* @noEscape */ $_menuHtml ?>
 <?= $block->getChildHtml() ?>
 </ul>
</nav>

1 Answer 1

2

Finally got the solution by updating menu-mixin.js

define([
 'jquery',
 ],
 function ($) {
 return function () {
 $.widget('mage.custommenu', $.mage.menu, {
 _toggleDesktopMode: function () {
 var html, subMenus;
 $(this.element).off('click mousedown mouseenter mouseleave');
 
 this._on({
 /**
 * Prevent focus from sticking to links inside menu after clicking
 * them (focus should always stay on UL during navigation).
 */
 'mousedown .ui-menu-item > a': function (event) {
 event.preventDefault();
 },
 /**
 * Prevent focus from sticking to links inside menu after clicking
 * them (focus should always stay on UL during navigation).
 */
 'click .ui-state-disabled > a': function (event) {
 event.preventDefault();
 },
 /**
 * @param {jQuer.Event} event
 */
 'click .ui-menu-item:has(a)': function (event) {
 var target = $(event.target).closest('.ui-menu-item');
 if (!this.mouseHandled && target.not('.ui-state-disabled').length) {
 this.select(event);
 // Only set the mouseHandled flag if the event will bubble, see #9469.
 if (!event.isPropagationStopped()) {
 this.mouseHandled = true;
 }
 if (!this.element.is(':focus') &&
 $(this.document[0].activeElement).closest('.ui-menu').length
 ) {
 // Redirect focus to the menu
 this.element.trigger('focus', [true]);
 // If the active item is on the top level, let it stay active.
 // Otherwise, blur the active item since it is no longer visible.
 if (this.active && this.active.parents('.ui-menu').length === 1) { //eslint-disable-line
 clearTimeout(this.timer);
 }
 }
 }
 subMenus = this.element.find('.level-top');
 $.each(subMenus, $.proxy(function (index, item) {
 var category = $(item).find('> a span').not('.ui-menu-icon').text(),
 categoryUrl = $(item).find('> a').attr('href'),
 menu = $(item).find('> .ui-menu');
 this.categoryLink = $('<a>')
 .attr('href', categoryUrl)
 .text($.mage.__('%1').replace('%1', category));
 this.categoryParent = $('<li>')
 .addClass('ui-menu-item all-category')
 .html(this.categoryLink);
 if (menu.find('.all-category').length === 0) {
 menu.prepend(this.categoryParent);
 }
 }, this));
 },
 /**
 * @param {jQuery.Event} event
 */
 'click .ui-menu-item.parent': function (event) {
 var target = $(event.target).closest('.ui-menu-item');
 if ($(target).hasClass('parent')) {
 event.preventDefault();
 }
 var target = $(event.currentTarget),
 submenu = this.options.menus,
 ulElement,
 ulElementWidth,
 width,
 targetPageX,
 rightBound;
 if (target.has(submenu)) {
 ulElement = target.find(submenu);
 ulElementWidth = ulElement.outerWidth(true);
 width = target.outerWidth() * 2;
 targetPageX = target.offset().left;
 rightBound = $(window).width();
 if (ulElementWidth + width + targetPageX > rightBound) {
 ulElement.addClass('submenu-reverse');
 }
 if (targetPageX - ulElementWidth < 0) {
 ulElement.removeClass('submenu-reverse');
 }
 }
 // Remove ui-state-active class from siblings of the newly focused menu item
 // to avoid a jump caused by adjacent elements both having a class with a border
 target.siblings().children('.ui-state-active').removeClass('ui-state-active');
 this.focus(event, target);
 },
 /**
 * @param {jQuery.Event} event
 */
 'click .ui-menu-item': function (event) {
 var target = $(event.target).closest('.ui-menu-item');
 if ($(target).hasClass('level0')) {
 return;
 }
 var target = $(event.currentTarget),
 submenu = this.options.menus,
 ulElement,
 ulElementWidth,
 width,
 targetPageX,
 rightBound;
 if (target.has(submenu)) {
 ulElement = target.find(submenu);
 ulElementWidth = ulElement.outerWidth(true);
 width = target.outerWidth() * 2;
 targetPageX = target.offset().left;
 rightBound = $(window).width();
 if (ulElementWidth + width + targetPageX > rightBound) {
 ulElement.addClass('submenu-reverse');
 }
 if (targetPageX - ulElementWidth < 0) {
 ulElement.removeClass('submenu-reverse');
 }
 }
 // Remove ui-state-active class from siblings of the newly focused menu item
 // to avoid a jump caused by adjacent elements both having a class with a border
 target.siblings().children('.ui-state-active').removeClass('ui-state-active');
 this.focus(event, target);
 },
 });
 $('.ui-menu-item').click(function () {
 $(this).children('ul').toggle();
 console.log("Click menu item")
 });
 html = $('html');
 if (html.hasClass('nav-open')) {
 html.removeClass('nav-open');
 setTimeout(function () {
 html.removeClass('nav-before-open');
 }, this.options.hideDelay);
 }
 },
 _toggleMobileMode: function () {
 var subMenus;
 $(this.element).off('mouseenter mouseleave');
 this._on({
 /**
 * @param {jQuery.Event} event
 */
 'click .ui-menu-item:has(a)': function (event) {
 var target;
 event.preventDefault();
 target = $(event.target).closest('.ui-menu-item');
 target.get(0).scrollIntoView();
 if (!target.hasClass('level-top') || !target.has('.ui-menu').length) {
 window.location.href = target.find('> a').attr('href');
 }
 },
 /**
 * @param {jQuery.Event} event
 */
 'click .ui-menu-item:has(.ui-state-active)': function (event) {
 this.collapseAll(event, true);
 }
 });
 $('.ui-menu-item').click(function () {
 $(this).children('ul').toggle();
 console.log("Click menu item")
 });
 subMenus = this.element.find('.level-top');
 $.each(subMenus, $.proxy(function (index, item) {
 var category = $(item).find('> a span').not('.ui-menu-icon').text(),
 categoryUrl = $(item).find('> a').attr('href'),
 menu = $(item).find('> .ui-menu');
 this.categoryLink = $('<a>')
 .attr('href', categoryUrl)
 .text($.mage.__('%1').replace('%1', category));
 this.categoryParent = $('<li>')
 .addClass('ui-menu-item all-category')
 .html(this.categoryLink);
 if (menu.find('.all-category').length === 0) {
 menu.prepend(this.categoryParent);
 }
 }, this));
 },
 focus: function () {
 return false;
 },
 });
 return $.mage.custommenu;
 }
 });
answered Oct 27, 2022 at 14:17
1
  • I was having same problem here. Thank you! Commented Dec 22, 2022 at 9:44

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.