1

I'm in the process of creating a responsive drop-down menu. The menu consists of three levels. Each item in this menu is a link. I would like the item from the menu to drop-down with the next menu level, when you click on the same link for the first time, I would like the user to be redirected to the page he chose. I managed to create a script that adds a class, so that the menu will drop down and close with a second click. Now I would like to add functionality that will allow me to redirect.

The active class switches the class with property: display: block;

I've already tried to add the preventDefault() function to my script, which blocks redirection from links, but I'd like to unlock it with a second click.

JQuery code:

$(document).ready(function(){
    $('.menu-item-has-children').click(function(e){
        e.preventDefault();
        $(this).children('.sub-menu').toggleClass("active");
        return false;
    });
});

HTML code:

<ul id="main-menu" class="main-nav">
  <li id="menu-item-759" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-759"><a href="http://example.com">Page 1</a></li>
  <li id="menu-item-760" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-760"><a href="#">Page 2</a></li>
  <li id="menu-item-761" class="menu-item menu-item-type-post_type menu-item-object-page current-page-ancestor current-menu-ancestor current_page_ancestor menu-item-has-children menu-item-761"><a href="#">Page 3</a>
    <ul class="sub-menu">
      <li id="menu-item-762" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-762"><a href="#">Subpage 1</a></li>
      <li id="menu-item-763" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-763"><a href="#">Subpage 2</a></li>
      <li id="menu-item-764" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-764"><a href="http://example.com">Subpage 3</a></li>
      <li id="menu-item-765" class="menu-item menu-item-type-post_type menu-item-object-page current-page-ancestor current-menu-ancestor current-menu-parent current-page-parent current_page_parent current_page_ancestor menu-item-has-children menu-item-765"><a href="#">Subpage 4</a>
        <ul class="sub-menu">
          <li id="menu-item-766" class="menu-item menu-item-type-post_type menu-item-object-page current-menu-item page_item page-item-192 current_page_item menu-item-766"><a href="http://example.com" aria-current="page">SubSubPage 1</a></li>
          <li id="menu-item-767" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-767"><a href="http://example.com">SubSubPage 2</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>
nsog8sm43x
  • 329
  • 5
  • 14

2 Answers2

1

Ok what I understand from you is : you want the second click to be default click without preventing it, right??

  • Dynamically Add class to the clicked element clicked using addClass()

  • Then prevent the click from this class clicked by using :not('.clicked') selector '.menu-item-has-children:not(.clicked)'

  • No need to use both e.preventDefault() and return false;


$(document).ready(function(){
    $(document).on('click' , '.menu-item-has-children:not(.clicked)' ,function(e){
        e.preventDefault();
        /* Optional */ $(this).closest('ul').find('.menu-item-has-children').removeClass('clicked'); // remove class clicked if use clicking on another `.menu-item-has-children` element
        $(this).addClass("clicked").children('.sub-menu').addClass("active");
    });
    
    /* Optional If you'll redirect the user to a new tab/window and still need the element to hide the dropdown menu  add another click event*/
    $(document).on('click' , '.menu-item-has-children.clicked' , function(e){
       $(this).removeClass("clicked").children('.sub-menu').removeClass("active");
    });
});
  • In this case we added a class clicked dynamically this is why we need to use [1]$(document).on('click' , '.menu-item-has-children:not(.clicked)' ,function(e){

REF[1]: Event binding on dynamically created elements?

Mohamed-Yousef
  • 23,946
  • 3
  • 19
  • 28
  • What properties in the style sheet should the class `clicked` have? – nsog8sm43x Jun 25 '20 at 17:28
  • @nsog8sm43x Nothing related with the style sheet .. its a dynamically javascript class to control what javascript doing .. its not a class for styling – Mohamed-Yousef Jun 25 '20 at 17:30
  • I'm sorry, but something in this script is not working, maybe it's my fault because I didn't put the HTML code. I'll edit the question in a minute. – nsog8sm43x Jun 25 '20 at 17:49
  • Sorry, my mistake. The HTML code doesn't change anything. Everything works the way I wanted it to, but there is one complication. The menu has another level three with the same classes. When I click on the second nested menu, the first one closes. – nsog8sm43x Jun 25 '20 at 18:06
  • Sorry @nsog8sm43x but I can't imagine the whole picture .. Specially your html code doesn't have any element with `menu-item-has-children` class .. if you please you can make `[<>]` snippet/demo with your actual code to let me or anyone understand your issue. – Mohamed-Yousef Jun 25 '20 at 18:19
  • Hello again, I found one error in the code. The script you created blocks the display of links in the submenu of the page version on high-resolution devices such as a laptop. It works correctly on mobile devices. – nsog8sm43x Jun 26 '20 at 07:50
  • OK, I solved it by `if($(window).width() >= 1024){}` – nsog8sm43x Jun 26 '20 at 07:57
  • But I found one mistake. The third level menu does not work on mobile devices. I prepared a fiddle. Could you check and tell me what's wrong ? My fiddle: https://jsfiddle.net/nsog8sm43x/zjdc0y6t/4/ – nsog8sm43x Jun 26 '20 at 08:22
  • I have investigated the issue in the development tools and it appears that the `clicked` class is not added to the `li` selector in the last menu level. I don't know if this changes anything in the operation of the script ? But if it doesn't work, then maybe it... ? – nsog8sm43x Jun 26 '20 at 08:41
  • @nsog8sm43x I updated my answer with `/* Optional $(this).closest*/` .. I don't prefer to add event inside `if` I prefer to use `if` inside the event https://jsfiddle.net/3ovfb8z9/ – Mohamed-Yousef Jun 26 '20 at 08:43
  • @nsog8sm43x And about the third level dropdown ..its already doesn't have any `menu-item-has-children` class – Mohamed-Yousef Jun 26 '20 at 08:47
  • I've added your new code, but it makes it impossible for me to see the third level of the menu at all... – nsog8sm43x Jun 26 '20 at 08:50
  • There are two submenus with a class of `sub-menu`. The second is the third level. – nsog8sm43x Jun 26 '20 at 08:51
  • I'm sorry, maybe I was in a bad rush. The third level works properly (displayed), but the redirection to the link from the last level does not work. I can't open the page like this. – nsog8sm43x Jun 26 '20 at 08:53
  • @nsog8sm43x Did you checked the fiddle I sent it to you? https://jsfiddle.net/3ovfb8z9/ – Mohamed-Yousef Jun 26 '20 at 08:58
  • Yes, but with this example, when you click on the `li` from the submenu, I am immediately redirected to the page below it. – nsog8sm43x Jun 26 '20 at 09:04
  • I think it might be a class name problem. The second and third menus have the same class names of `.menu-item-has-children` and `.submenu`. The classes are automatically generated by wordpress. I don't know. Does it matter ? – nsog8sm43x Jun 26 '20 at 09:15
  • @nsog8sm43x I can't tell I'm not expert in wordpress but for me its not a big deal for the menus to have a same class .. maybe different classes will be easier to work with .. Anyways you can add `wordpress` in your question tags may be someone has another idea – Mohamed-Yousef Jun 26 '20 at 09:19
  • Could you take a look at my side? Maybe this will give you a better insight. – nsog8sm43x Jun 26 '20 at 09:27
  • OK, I found a solution. I had to change one thing in your code `$(this).removeClass('clicked');` instead of `$('.menu-item-has-children').removeClass('clicked');`. Thank you very much for bringing me closer to the solution, help and commitment :) – nsog8sm43x Jun 26 '20 at 10:23
  • Sorry @nsog8sm43x for not solving your problem as you expect me to do but you're totally welcome anyway .. Also `$(this).removeClass('clicked');` doesn't make any sense while you already use selector `:not(.clicked)` .. whatever, I'm really glad that you find a solution by your own .. Have a great day :-) – Mohamed-Yousef Jun 26 '20 at 11:15
  • Thank you. I accept your solution because it solved the first part of my problem. Only then did it turn out to be more complex. Thank you again for your help. Have a nice day! :) – nsog8sm43x Jun 26 '20 at 11:18
0

Here, you can maintain the variable to track the numbers of click on the menu,

keep the variable false initially, on first click change the value of variable to true and on second click in variable is true don't call preventDefault() method.

the code would be like the below lines:

$(document).ready(function(){
  var myVar= false
$('.menu-item-has-children').click(function(e){
   if(myVar === false)
   { e.preventDefault();}
    myVar = !myVar;
    $(this).children('.sub-menu').toggleClass("active");
    return false;
});
});
Minal Shah
  • 1,402
  • 1
  • 5
  • 13
  • Unfortunately @Minal this case can't be solved with boolen variable .. Because if the use click on the element the `myVar` will change to true and if the user click on another `'.menu-item-has-children'` element the `myVar` will remain true .. just think about it :-) .. Also No need for `return false;` it will work like `e.preventDefault();` – Mohamed-Yousef Jun 25 '20 at 17:17