Search code examples
javascriptjquerymodularityslideuptabbing

SlideUp not firing after first time triggered on tabbing module


I have a tabbing module that I'm beginning to modularise. The basic functionality is working but the slideUp function doesn't seem to be firing after the first time it is triggered. Instead tabs are just laying over the top of one another.

(function() {


  var tabbing = {
    init: function() {
      this.cacheDom();
      this.bindEvents();
    },
    cacheDom: function() {
      this.el = $('.js-tab-panels');
      this.tabs = this.el.find('.js-tabs');
      this.navItem = this.tabs.find('.nav-item');
      this.panel = this.navItem.closest(this.el);
    },
    bindEvents: function() {
      this.navItem.on('click', this.toggleActive.bind(this));
    },
    toggleActive: function(el) {
      this.panel.find('.js-tabs li.active').removeClass('active');
      var add = $(el.target).closest(this.navItem);
      add.addClass('active');

      this.hidePanel();
    },
    hidePanel: function() {
      this.panel.find('.panel.active').slideUp(300, this.showPanel());

    },
    showPanel: function() {
      var panelToShow = this.panel.find('.js-tabs li.active').attr('rel');
      this.panel.find('.panel.active').removeClass('active');
      $('#' + panelToShow).slideDown(300, function() {
        $(this).addClass('active');
      });
    }


  };

  tabbing.init();

})()
body {
  background: #fafafa;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  color: #333;
}

.tab-panels ul {
  margin: 0;
  padding: 0;
}

.tab-panels ul li {
  list-style-type: none;
  display: inline-block;
  background: #999;
  margin: 0;
  padding: 3px 10px;
  border-radius: 10px 10px 0 0;
  color: #fff;
  font-weight: 200;
  cursor: pointer;
}

.tab-panels ul li:hover {
  color: #fff;
  background: #666;
}

.tab-panels ul li.active {
  color: #fff;
  background: #666;
}

.tab-panels .panel {
  display: none;
  background: #c9c9c9;
  padding: 30px;
  border-radius: 0 0 10px 10px;
}

.tab-panels .panel.active {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="js-tab-panels tab-panels">
  <ul class="js-tabs tabs">
    <li rel="panel1" class="nav-item active">panel1</li>
    <li rel="panel2" class="nav-item">panel2</li>
    <li rel="panel3" class="nav-item">panel3</li>
    <li rel="panel4" class="nav-item">panel4</li>
  </ul>

  <div id="panel1" class="panel active">
    content1<br/> content1
    <br/> content1
    <br/> content1
    <br/> content1
    <br/>
  </div>
  <div id="panel2" class="panel">
    content2<br/> content2
    <br/> content2
    <br/> content2
    <br/> content2
    <br/>
  </div>
  <div id="panel3" class="panel">
    content3<br/> content3
    <br/> content3
    <br/> content3
    <br/> content3
    <br/>
  </div>
  <div id="panel4" class="panel">
    content4<br/> content4
    <br/> content4
    <br/> content4
    <br/> content4
    <br/>
  </div>
</div>


Solution

  • In the hidePanel function when you call .slideUp(300, this.showPanel()); you are passing the result of this.showPanel() as the second argument of slideUp function, but what you want is to execute this.showPanel as the callback when slideUp animation is complete.

    So to fix that you just need to pass in a copy of the showPanel function as the second argument instead of its result:

    ...slideUp(300, this.showPanel.bind(this));