0

I am working on making a long page of links in a set of nested <ul>'s more user friendly with some jQuery and CSS. I am unable to directly edit the HTML, but I was able to write code to collapse the lists so that only the top level <li>'s display, and then when the user clicks one, it expands to show all the children.

The problem is that the top level items are also links. I want to disable the links when the <li> is collapsed (and has class .notActive), and reenable them when it's expanded (and has class .open), so that users can expand the menu without being taken away from the page.

Unfortunately, the solutions I've tried have either disabled the links 100% of the time (when using event.preventDefault();) or have disabled all clicking events (when using pointer-events:none;), which also disables the expanding/collapsing functions.

I've read similar questions, such as this one: How do I dynamically enable/disable links with jQuery? but haven't been able to figure out how to re-enable the links.

Here is my jsfiddle: https://jsfiddle.net/9raufx3s/121/ and here's what my code currently looks like:

CODE:

$(document).ready(function($) {

 $(".children").closest("li").addClass("hasSubmenu");

 if ($("li").hasClass("hasSubmenu")) {
  $("li.hasSubmenu").append("<span class='plus'>&nbsp;&nbsp;&#43;</span>");
 }

 $(".cat-item").click(function(e) {
  $(this).toggleClass("open");
  e.stopPropagation();
 });
});

$("ul.category-column").after("<p class='all'>Expand All</p>");
$("p.all").click(function(f) {
 $(".cat-item").addClass("open");
});

$(document).ready(function($) {
 var top = $("ul.category-column li.hasSubmenu").first();
 top.addClass("topLevel notActive");
 top.siblings("li").addClass("topLevel notActive");

 $("li.topLevel").click(function(n) {
  $(this).toggleClass("notActive");
 });
});
$(document).ready(function($) {
 $("li.notActive a").on('click', function(disabled) {
  disabled.preventDefault();
 });
 $("li.open a").on('click', function(enabled) {
  return true;
 });
});
li.open * {
  display:block !important;
}    
.children {
  display:none;
}    
li.open>span.plus {
  display:none !important;
}    
li.open>ul.children>li.hasSubmenu>span.plus {
  display:none !important;
}    
.all {
  font-weight:bold;
  cursor:pointer;
}    
.notActive {
  color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="category-column">
 <li class="cat-item cat-item-3"><a href="https://www.google.com">I. Heading Number One</a>
  <ul class="children">
   <li class="cat-item cat-item-481"><a href="#">Subheading A</a></li>
   <li class="cat-item cat-item-483"><a href="https://www.google.com">Subheading B</a>
    <ul class="children">
     <li class="cat-item cat-item-587">Child of subheading B</li>
     <li class="cat-item cat-item-588">Second child of subheading B</li>
    </ul>
   </li>
  </ul>
 </li>

 <li class="cat-item cat-item-4">II.Heading Number Two
  <ul class="children">
   <li class="cat-item cat-item-200"><a href="#">Subheading C</a></li>
   <li class="cat-item cat-item-201"><a href="#">Subheading D</a>
    <ul class="children">
     <li class="cat-item cat-item-300">Child of subheading D</li>
     <li class="cat-item cat-item-301">Second Child of subheading D</li>
    </ul>
   </li>
  </ul>
 </li>
</ul>
Calvin Nunes
  • 6,376
  • 4
  • 20
  • 48
Karen
  • 38
  • 1
  • 1
  • 6
  • How about the solutions mentioned in this thread? https://stackoverflow.com/questions/7610871/how-to-trigger-an-event-after-using-event-preventdefault – Dincă Alexandru Sep 19 '18 at 20:35

1 Answers1

1

To answer your question about undoing preventDefault - you could work with Event binding and unbinding, as a simplified showcase:

function generic(evt) {
  console.log('generic');
  $('.toggable', this).toggleClass('hidden');
};

function toggle(evt) {
  console.log('prevents');
  evt.stopPropagation();
  evt.preventDefault();
}

$('.toggle').on('click', function() {
  var $this = $(this),
      $target = $('.target');
  if($this.hasClass('prevents')) {
    $target.unbind('click', toggle);
    $this.removeClass('prevents');
  } else {
    $target.bind('click', toggle);
    $this.addClass('prevents');
  }
});

$('.target').bind('click', generic);
.hidden { display: none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="https://duckduckgo.com/" class="target" target="_blank">Duck<span class="toggable hidden">(toggable)</span></a>

<hr>

<a href="#" class="toggle">Toggle handler</a>

But for your use-case you could do it in an easier and more efficient manner, again as a simplified showcase:

$('li').each(function() {
  var $this = $(this),
      $children = $('>ul', this),
      $link = $('>a', this);
  $this.on('click', function(evt) {
    console.log('li clicked, propagation stopped');
    // Don't bubble up collapsing
    evt.stopPropagation();
    $children.toggleClass('open');
  });
  $link.on('click', function(evt) {
    if($children.length === 0 || $children.hasClass('open')) {
      // If children are expanded or there are no children
      // only prevent bubbling up the event
      console.log('link clicked, propagation stopped');
      evt.stopPropagation();
    } else {
      // If children are not expanded yet
      console.log('link clicked, default prevented');
      evt.preventDefault();
    }
  });
});

var collapsed = true;
$('.toggle-all').on('click', function(evt) {
  evt.stopPropagation();
  evt.preventDefault();
  if(collapsed) {
    $('ul').addClass('open');
    collapsed = false;
  } else {
    $('ul').removeClass('open');
    collapsed = true;
  }
});
li>ul { display: none; }
li>ul.open { display: block; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
  <li>Parent
    <ul>
      <li>Child</li>
      <li>Child</li>
    </ul>
  </li>
  <li><a href="#">Parent</a>
    <ul>
      <li><a href="#">Child</a></li>
      <li>Child</li>
    </ul>
  </li>
</ul>

<a href="#" class="toggle-all">Toggle all</a>
wiesion
  • 2,349
  • 12
  • 21
  • Thank you, this almost works! The only problem I'm still running into is that there's a third level of children on my site, and they don't expand. When you click on their parent li, it just collapses everything back instead of expanding the next level of children. I'll work on it myself, but if you have any suggestions on how to get all descendants to expand/collapse, they'd be appreciated! Edit: Nevermind, it works! – Karen Sep 20 '18 at 19:25