Jarad
Jarad

Reputation: 18883

Recursively Expand Bootstrap 4 Sidebar To Previous State When Hitting Back In Browser

The below HTML, CSS, Bootstrap 4 code produces an accordion-style expandable/collapsible sidebar menu that looks like this:

sidebar-accordion-dropdown-menu

What I'm trying to do

Either via Bootstrap 4 OR jQuery OR straight Javascript...

If I click the "Push Mowers" link and then click back, I want the sidebar to expand all parent nodes above showing the "Push Mowers" item again. This means the sidebar would need to expand (show): Gardening, Equipment and Lawn Mowers in-order to show the previously-clicked item "Push Mowers".

My first attempt to solve this is to add a URL Fragment to the last item clicked using Javascript:

<script>
  $('.list-group').on('click', '.list-group-item', function(){
      var clickedID = this.id;
      // alert(clickedID);
      window.location.hash = clickedID;
  });
</script>

Next, I'm not sure how to proceed. I started down this path but this looks horribly and inefficient especially since I'm using Bootstrap 4.

// probably a terrible idea
<script>
  if(window.location.hash) {
      var hash = window.location.hash.slice(1);
      var elem = document.getElementById(hash);
      var node = elem.hash.slice(1);
      var x = document.getElementById(node);
      x.classList.add('show');
      console.log(x);
      var pn = x.parentNode;
      console.log(pn.getAttribute('href'))
  } else {
    // Fragment doesn't exist
  }
</script>

I'm really unclear how to recursively expand all parent categories above a given node.

The Reproducible HTML, CSS, Bootstrap:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css">

<style>
  .leve-0 {
    padding-left: 15px;
  }
  .level-1 {
    padding-left: 30px;
  }
  .level-2 {
    padding-left: 45px;
  }
  .level-3 {
    padding-left: 60px;
  }
</style>

<div class="container-fluid">
  <div class="row">
    <div class="text-nowrap">
      <div id="sidebar">
        <div class="list-group panel">
          <a href="#node11" class="list-group-item level-0" data-parent="#sidebar" data-toggle="collapse"
             aria-expanded="true" id="gardening">Gardening <i class="fa fa-caret-down"></i></a>
          <div class="collapse" id="node11">
            <a href="#node13" class="list-group-item level-1" data-parent="#node13" data-toggle="collapse"
            id="lawn-chemicals">Lawn Chemicals <i class="fa fa-caret-down"></i></a>
            <div class="collapse" id="node13">
              <a href="gardening/lawn-chemicals/moss-control/" class="list-group-item level-2" data-parent="#node13"
              id="moss-control">Moss Control</a>
            </div>
            <a href="#node14" class="list-group-item level-1" data-parent="#node14" data-toggle="collapse"
            id="equipment">Equipment <i class="fa fa-caret-down"></i></a>
            <div class="collapse" id="node14">

              <a href="#node15" class="list-group-item level-2" data-parent="#node15" data-toggle="collapse"
              id="lawn-mowers">Lawn Mowers <i class="fa fa-caret-down"></i></a>
              <div class="collapse" id="node15">
                <a href="gardening/equipment/lawn-mowers/push-mowers/" class="list-group-item level-3" data-parent="#node15"
                id="push-mowers">Push Mowers</a>
                <a href="gardening/equipment/lawn-mowers/riding-mowers/" class="list-group-item level-3" data-parent="#node15"
                id="riding-mowers">Riding Mowers</a>
            </div>
              <a href="gardening/equipment/weed-wackers/" class="list-group-item level-2" data-parent="#node15"
              id="weed-wackers">Weed Wackers</a>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Upvotes: 0

Views: 614

Answers (1)

bigless
bigless

Reputation: 3091

You need only to traverse DOM up and it is quite easy with jQuery:

// just mocking history back
var historyHashArray = [
  "push-mowers",
  "equipment",
  "gardening",
  "moss-control",
];

var currentHistoryIndex = 0;

// get reverse order of $ elements
jQuery.fn.reverse = [].reverse;

function expandTree() {
  if (currentHistoryIndex < historyHashArray.length) {
    console.log(historyHashArray[currentHistoryIndex]);
    $('.collapse').removeClass('show'); // resets
    $('#' + historyHashArray[currentHistoryIndex])
      .parents('.collapse')
      .reverse()
      .collapse('show');
    currentHistoryIndex++;
  }
}

document.getElementById('back-btn').onclick = expandTree;
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css">

<style>
  .leve-0 {
    padding-left: 15px;
  }
  .level-1 {
    padding-left: 30px;
  }
  .level-2 {
    padding-left: 45px;
  }
  .level-3 {
    padding-left: 60px;
  }
</style>

<button type="button" id="back-btn" class="mb-3">History Back</button>

<div class="container-fluid">
  <div class="row">
    <div class="text-nowrap">
      <div id="sidebar">
        <div class="list-group panel">
          <a href="#node11" class="list-group-item level-0" data-toggle="collapse"
             aria-expanded="true" id="gardening">Gardening <i class="fa fa-caret-down"></i></a>
          <div class="collapse" id="node11">
            <a href="#node13" class="list-group-item level-1" data-toggle="collapse"
            id="lawn-chemicals">Lawn Chemicals <i class="fa fa-caret-down"></i></a>
            <div class="collapse" id="node13">
              <a href="gardening/lawn-chemicals/moss-control/" class="list-group-item level-2" id="moss-control">Moss Control</a>
            </div>
            <a href="#node14" class="list-group-item level-1" data-toggle="collapse" id="equipment">Equipment <i class="fa fa-caret-down"></i></a>
            <div class="collapse" id="node14">

              <a href="/" class="list-group-item level-2" data-toggle="collapse" id="lawn-mowers">Lawn Mowers <i class="fa fa-caret-down"></i></a>
              <div class="collapse" id="node15">
                <a href="/" class="list-group-item level-3" id="push-mowers">Push Mowers</a>
                <a href="/" class="list-group-item level-3" id="riding-mowers">Riding Mowers</a>
            </div>
              <a href="gardening/equipment/weed-wackers/" class="list-group-item level-2" id="weed-wackers">Weed Wackers</a>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Update: So with your click event, it should be something like

$(document).ready(function() {
  if (window.location.hash) {
    var id = window.location.hash; // luckily it already includes #
    $(id).parents('.collapse').collapse('show');
  }
});

Upvotes: 1

Related Questions