Bootstrap dropdown - shown.bs.dropdown event not firing after css transition

11,372

Solution 1

For everyone having this problem i'll post here how i managed to work around this issue/problem.

Basically i set the fade in class when the user clicks and let it there until the menu is closing. If the menu starts to close, the fadeIn class is removed, the fadeOut class is added and after the animation is complete (handeled by the jquery .on([animationEndSelectors])) i remove the fadeOut class and close the submenu (by revmoving the open class on the ul).

var animationEndSelectors = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';
var inAnimation = 'animated ' + 'fadeInDown';
var outAnimation = 'animated ' + 'fadeOutUp';

$('#userMenu').on({
    "show.bs.dropdown": function () {
        $('.dropdown-menu', this).addClass(inAnimation);
    },
    "hide.bs.dropdown":  function() {
        var ddl = this;

        $(ddl).addClass('closing');
        $('.dropdown-menu', this).removeClass(inAnimation);
        $('.dropdown-menu', this).addClass(outAnimation);
        $('.dropdown-menu', this).one(animationEndSelectors, function () {
            $('.dropdown-menu', ddl).removeClass(outAnimation);
            $(ddl).removeClass('open closing');
        });
        return false;
    }
});

Solution 2

You just need to create delays for when the animation classes are added/removed. For the "hide" event, you'll need to prevent Bootstrap from hiding it too soon by manually removing the open class after your animation classes are added...

$('#userMenu').on({
  "shown.bs.dropdown": function () {
    $(this).find('.dropdown-menu').addClass('animated fadeInDown');
    setTimeout(function(){
        $('.dropdown-menu').removeClass('animated fadeInDown');
    },1000);
  },
  "hide.bs.dropdown":  function(e) {
    e.preventDefault();
    $(this).find('.dropdown-menu').addClass('animated fadeOutUp');
    setTimeout(function(){
        $('.dropdown-menu').removeClass('animated fadeOutUp').parent().removeClass('open');
    },1000);
  }
});

Demo: http://bootply.com/iZObFaEJwr

Share:
11,372
fDruga
Author by

fDruga

Updated on June 15, 2022

Comments

  • fDruga
    fDruga almost 2 years

    I have this problem with the shown.bs.dropdown event handler for the bootstrap dropdown. At the show event i set the animation class and i want that after the animation is complete to remove the class. Unfortunately the event is firing immediately after the show event.

    I tried applying the class in the attribute at runtime (thought that this way bootstrap will be aware about the css transition to be applied and to delay the shown event) but with no result. The animation classes are provided by animate.css library. I set up a fiddle to show my issue. - http://jsfiddle.net/u08bt6ck/

    Here is my markup:

    <ul class="nav navbar-nav">
        <li id="userMenu" class="dropdown">
            <a href="#" data-toggle="dropdown" class="dropdown-toggle">Open me</a>
            <ul class="dropdown-menu">
                <li><a href="#"><i class="fa fa-sliders"></i>lnk 1</a></li>
                <li><a href="#"><i class="fa fa-user"></i>lnk 2</a></li>
                <li><a href="#"><i class="fa fa-clock-o"></i>lnk 3</a></li>
            </ul>
        </li>
    </ul>
    

    And this is the js:

    $('#userMenu').on({
        "show.bs.dropdown": function () {
            $('.dropdown-menu', this).addClass('animated fadeInDown');
        },
        "shown.bs.dropdown": function () {
            $('.dropdown-menu', this).removeClass('animated fadeInDown');
        },
        "hide.bs.dropdown":  function() {
            $('.dropdown-menu', this).addClass('animated fadeOutDown');
        },
        "hidden.bs.dropdown": function () {
            $('.dropdown-menu', this).removeClass('animated fadeOutDown');
            //alert('ni ca s-a terminat');
        }
    });
    
  • fDruga
    fDruga about 9 years
    Using your method fires 'shown' immediatly after 'show' thus removing the classes before the animation to even start.
  • fDruga
    fDruga about 9 years
    Thanks for the answer! Eventually i had implemented this solution myself but instead of setTimeout i used css animationend pseudo states. This way you can set the animation delay whatever you want in css and the handler will always fire at the right time. You can check my own answer at this question. Anyway i think of this implementation more of like a workaround because the hided handler should had fired after the css transitions (from bootstrap documentation) thus removing the need of using timers or pseudo-css selectors.