Ian Hazzard
Ian Hazzard

Reputation: 7771

How to calculate a speed for slideToggle()

I have a navigation menu with several accordion-style items. Some "parent" links have more children than others. I'd like to vary the speed of the slideToggle() so that the ones with more children take longer to slideDown(). Here is what I tried, but it's jumping around for some reason. There's no easing happening at all, as you can see.

// Get the height of each list and save it in the data-height attribute
$('.main-nav > ul > li > ul').each(function() {
  $(this).slideDown(0);
  $(this).data('height', $(this).height());
  $(this).slideUp(0);
});

$('.main-nav > ul > li').click(function() {
  // Multiply the height of the element by the speed desired
  $(this).children().slideToggle($(this).data('height') * 1000, 'easeInOutExpo');
});
.main-nav {
  position: fixed;
  top: 0;
  left: 0;
}
.main-nav ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
  font-size: 18px;
}
.main-nav ul li {
  padding: 22px 0;
  cursor: pointer;
}
.main-nav > ul {
  padding: 0 22px;
}
.main-nav > ul > li > ul {
  display: none;
}
*,
*:before,
*:after {
  box-sizing: border-box;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js"></script>
<nav class="main-nav">
  <ul>
    <li>Global
      <ul>
        <li>Typography</li>
        <li>Colors</li>
        <li>Icons</li>
      </ul>
    </li>
    <li>Elements
      <ul>
        <li>Text</li>
        <li>Buttons</li>
        <li>Lists</li>
        <li>Tables</li>
        <li>Media</li>
      </ul>
    </li>
    <li>Controls
      <ul>
        <li>dropdown</li>
        <li>alerts</li>
        <li>badges</li>
        <li>modals</li>
      </ul>
    </li>
    <li>Layout
      <ul>
        <li>dynamic row</li>
        <li>flex</li>
      </ul>
    </li>
    <li>Components
      <ul>
        <li>cards</li>
        <li>banners</li>
        <li>itemEditor</li>
        <li>itemIndex</li>
        <li>jQueryUI</li>
        <li>login</li>
        <li>main</li>
        <li>details (and detail views)</li>
        <li>drilldown</li>
        <li>mega menu</li>
        <li>navigation</li>
        <li>search</li>
        <li>thick items</li>
        <li>widgets</li>
      </ul>
    </li>
  </ul>
</nav>

Upvotes: 3

Views: 387

Answers (2)

imtheman
imtheman

Reputation: 4843

Instead of going based off height, I'd recommend going based off how many li elements are in the ul (you may need to modify the multiplier if 1000 is too slow for you).

// Get the height of each list and save it in the data-height attribute
$('.main-nav > ul > li > ul').each(function() {
  $(this).slideUp(0);
});

$('.main-nav > ul > li').click(function() {
  // Multiply the height of the element by the speed desired
  $(this).children().slideToggle($(this).find("li").length * 1000, 'easeInOutExpo');
});
.main-nav {
  position: fixed;
  top: 0;
  left: 0;
}
.main-nav ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
  font-size: 18px;
}
.main-nav ul li {
  padding: 22px 0;
  cursor: pointer;
}
.main-nav > ul {
  padding: 0 22px;
}
.main-nav > ul > li > ul {
  display: none;
}
*,
*:before,
*:after {
  box-sizing: border-box;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js"></script>
<nav class="main-nav">
  <ul>
    <li>Global
      <ul>
        <li>Typography</li>
        <li>Colors</li>
        <li>Icons</li>
      </ul>
    </li>
    <li>Elements
      <ul>
        <li>Text</li>
        <li>Buttons</li>
        <li>Lists</li>
        <li>Tables</li>
        <li>Media</li>
      </ul>
    </li>
    <li>Controls
      <ul>
        <li>dropdown</li>
        <li>alerts</li>
        <li>badges</li>
        <li>modals</li>
      </ul>
    </li>
    <li>Layout
      <ul>
        <li>dynamic row</li>
        <li>flex</li>
      </ul>
    </li>
    <li>Components
      <ul>
        <li>cards</li>
        <li>banners</li>
        <li>itemEditor</li>
        <li>itemIndex</li>
        <li>jQueryUI</li>
        <li>login</li>
        <li>main</li>
        <li>details (and detail views)</li>
        <li>drilldown</li>
        <li>mega menu</li>
        <li>navigation</li>
        <li>search</li>
        <li>thick items</li>
        <li>widgets</li>
      </ul>
    </li>
  </ul>
</nav>

Upvotes: 1

Hans Strausl
Hans Strausl

Reputation: 615

$(this).data('height') appears to be undefined, so it appears that you end up passing NaN as the first arg to the slideToggle() function, I am not sure what the fix is but hopefully that points you in the right direction

Upvotes: 0

Related Questions