Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

twitter bootstrap dropdown doesn't toggle closed when it should

Oh man, I've been tearing my hair out over this. 4 hours on a dropdown.

I'm using Twitter Bootstrap.

The fixed nav at the top has a dropdown, pretty standard stuff.

Except that the dropdown doesn't get closed as it normally should. It will only toggle open and closed when the toggle itself is pressed, not when an item in the menu is pressed or the user clicks outside the menu (both of these should close the dropdown).

The only thing I'm doing non-standard is my use of an iframe and a theme from bootswatch.

I haven't had an issue like this before so I have a feeling it may be a bug (upgraded bootstrap to 2.1.0, and jquery to 1.7.2 today).

all the code here:

    <!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>test</title>
        <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
        <!--[if lt IE 9]> <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> <![endif]-->
        <!-- Le styles -->
        <link href="./css/bootstrap.css" rel="stylesheet">
        <style>
            iframe {
                border: 0px;
                height: 95%;
                left: 0px;
                position: absolute;
                top: 50px;
                width: 100%;
            }
        </style>
    </head>
    <body>
        <div class="navbar navbar-fixed-top">
            <div class="navbar-inner">
                <div class="container">
                    <a class="brand" target="mainframe" href="./home.html">
                       Brand
                    </a>
                    <ul class="nav">
                        <li class="dropdown">
                            <a href="#" class="dropdown-toggle" role="button" data-toggle="dropdown">
                                <i class="icon-pencil icon-white"></i>
                                Sample
                                <b class="caret"></b>
                            </a>
                            <ul class="dropdown-menu" role="menu">
                                <li>
                                    <a target="mainframe" href="./home.html#">One</a>
                                </li>
                                <li>
                                    <a target="mainframe" href="./home.html#">Two</a>
                                </li>
                                <li>
                                    <a target="mainframe" href="./home.html#">Three</a>
                                </li>
                                <li>
                                    <a target="_blank" href="#">Four
                                        <i class="icon-share-alt"></i>
                                    </a>
                                </li>
                                <li>
                                    <a target="_blank" href="#">Five
                                        <i class="icon-share-alt"></i>
                                    </a>
                                </li>
                            </ul>
                        </li>
                        <li>
                            <a href="#">
                                <i class="icon-certificate icon-white"></i>Stuff</a></li>
                        <li>
                            <a href="#">
                                <i class="icon-globe icon-white"></i>Things</a></li>
                        <li>
                            <a target="mainframe" href="./home.html">
                                <i class="icon-film icon-white"></i>Nothing</a></li>
                    </ul>
                </div>
            </div>
        </div>
        <div class="container">
            <iframe id="frame" name="mainframe" src="./home.html"></iframe>
            <!-- /container -->
        </div>
        <!-- Le javascript==================================================-->
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>

        <script src="./js/bootstrap.js"></script>
        <script type="text/javascript">
            $(document).ready(function () {
                $('.dropdown-toggle').dropdown();
                var frameheight = window.innerHeight - 50;
                document.getElementById("frame").style.height = frameheight + "px";
            });

            $(window).resize(function () {
                var frameheight = window.innerHeight - 50;
                document.getElementById("frame").style.height = frameheight + "px";
            });
        </script>
    </body>
</html>

live here: http://www.joshlevent.com/dropdownbug/

like image 670
Josh Avatar asked Aug 25 '12 17:08

Josh


4 Answers

iframes don't propagate click events up to their parents by default. You need to add code to do that manually. In addition to being able to edit the content of the iframe you are loading, cross-domain restrictions will require you to be loading the iframe content from the same domain as your page.

This would need to run from within the iframe page:

$('html').on('click', function () {
  parent.$('#frame').trigger('click');
});

where #frame is the id of your iframe. You could delegate the click to anything in the parent (e.g., 'body') and that would work as well. Depends on how tightly you want to couple the content in the iframe to the page.

So, that should take care of the page closing the menu.

Important Update

As for clicking on the menu items to close the menu, apparently there was a bug[?] in the lastest update (2.0.4 > 2.1.0): Dropdown menus don't get closed when selecting an option. A selector was changed from '.dropdown form' to '.dropdown', so now what was once a celebrated feature to make working with dropdowns in forms easier has evolved into a callback that blocks all clicks on dropdown menu items.

An interim solution is to include the following code until the bug is fixed (2.1.1):

$('body')
  .off('click.dropdown touchstart.dropdown.data-api', '.dropdown')
  .on('click.dropdown touchstart.dropdown.data-api'
    , '.dropdown form'
    , function (e) { e.stopPropagation() })
like image 102
merv Avatar answered Oct 11 '22 20:10

merv


Nothing worked for me, except this:

$('.dropdown-menu li a').on('click', function(e) {
    $('.dropdown-toggle').dropdown('toggle');
    e.stopPropagation();
});
like image 20
Denis Zarubin Avatar answered Oct 11 '22 20:10

Denis Zarubin


I was seeing the same problem with 2.1.1.

The solution that was posted on GitHub which worked easily for me was:

$('body').on('touchstart.dropdown', '.dropdown-menu', function (e) { e.stopPropagation(); });

Credit to blakeembrey at https://github.com/twitter/bootstrap/issues/5094

like image 2
Ivan Town Avatar answered Oct 11 '22 20:10

Ivan Town


This is the full solution I implemented based on merv's great answer. If there is a better way for me to post the solution for those coming in the future please let me know.

This jquery was added to the bottom of the html of the pages in the frame:

$('html').on('click', function () {
  parent.$('#frame').trigger('click');
});

The dropdown was switched to a button and restyled to fit into the navbar. In the html:

                <li class="btn-group" id="samplebtn">
                    <a href="#" class="btn btn-primary dropdown-toggle" role="button" data-toggle="dropdown">
                        <i class="icon-pencil icon-white"></i>
                        Sample
                        <b class="caret"></b>
                    </a>

In the CSS:

        #samplebtn {
        position:absolute;
        top: 0;
        margin: 0px;
        padding: 0px;
        border: 0px;
        }
        #samplebtn .btn {
            border: 0px;
        }

full code of solution (update of the full code in the question - this is the outside frame only):

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>test</title>
        <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
        <!--[if lt IE 9]> <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> <![endif]-->
        <!-- Le styles -->
        <link href="./css/bootstrap.css" rel="stylesheet">
        <style>
            iframe {
                border: 0px;
                height: 95%;
                left: 0px;
                position: absolute;
                top: 50px;
                width: 100%;
            }
            #samplebtn {
            position:absolute;
            top: 0;
            margin: 0px;
            padding: 0px;
            border: 0px;
            }
            #samplebtn .btn {
                border: 0px;
            }
        </style>
    </head>
    <body>
        <div class="navbar navbar-fixed-top">
            <div class="navbar-inner">
                <div class="container">
                    <a class="brand" target="mainframe" href="./home.html">
                       Brand
                    </a>
                    <ul class="nav">

                        <li class="btn-group" id="samplebtn">
                            <a href="#" class="btn btn-primary dropdown-toggle" role="button" data-toggle="dropdown">
                                <i class="icon-pencil icon-white"></i>
                                Sample
                                <b class="caret"></b>
                            </a>
                            <ul class="dropdown-menu" role="menu">
                                <li>
                                    <a target="mainframe" href="./home.html#">One</a>
                                </li>
                                <li>
                                    <a target="mainframe" href="./home.html#">Two</a>
                                </li>
                                <li>
                                    <a target="mainframe" href="./home.html#">Three</a>
                                </li>
                                <li>
                                    <a target="_blank" href="#">Four
                                        <i class="icon-share-alt"></i>
                                    </a>
                                </li>
                                <li>
                                    <a target="_blank" href="#">Five
                                        <i class="icon-share-alt"></i>
                                    </a>
                                </li>
                            </ul>
                        </li>
                        <li>
                            <a href="#">
                                <i class="icon-certificate icon-white"></i>Stuff</a></li>
                        <li>
                            <a href="#">
                                <i class="icon-globe icon-white"></i>Things</a></li>
                        <li>
                            <a target="mainframe" href="./home.html">
                                <i class="icon-film icon-white"></i>Nothing</a></li>
                    </ul>
                </div>
            </div>
        </div>
        <div class="container">
            <iframe id="frame" name="mainframe" src="./home.html"></iframe>
            <!-- /container -->
        </div>
        <!-- Le javascript==================================================-->
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>

        <script src="./js/bootstrap.js"></script>
        <script type="text/javascript">
            $(document).ready(function () {
                $('.dropdown-toggle').dropdown();
                var frameheight = window.innerHeight - 50;
                document.getElementById("frame").style.height = frameheight + "px";
            });

            $(window).resize(function () {
                var frameheight = window.innerHeight - 50;
                document.getElementById("frame").style.height = frameheight + "px";
            });

            $('.dropdown-menu').on('click', function () {
              $('.dropdown-toggle').dropdown();
            });
        </script>
    </body>
</html>

for complete reference, this is the code of a page inside the frame:

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="utf-8">
        <title>Title</title>

        <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
        <!--[if lt IE 9]>
            <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
        <![endif]-->
        <!-- Le styles -->
        <link href="./bootstrap.min.css" rel="stylesheet">
        <style>

        </style>
    </head>

    <body onload="scrollTo(0,0); $('#loading').css('display','none');">
        <div id="loading" style="width: 100%; height: 100%; background-color: white; background-image:url('loader.gif'); background-repeat:no-repeat; background-position: center center; position:fixed; display: none; z-index:100;"></div>
        <script type="text/javascript">
            document.getElementById("loading").style.display = 'block';
        </script>


        <div class="container">
        <div class="span12">
                    <h2>Project Description</h2>
                    <p>Lorem Ipsum Dolor Sit Amet</p>


                </div>

            <!-- /container -->
        </div>
        <!-- Le javascript==================================================-->

        <script src="./jquery.js"></script>
        <script src="./bootstrap.min.js"></script>
<!--        <script src="./bootstrap-dropdown.js"></script>
-->
<script>
$('html').on('click', function () {
  parent.$('#frame').trigger('click');
});

</script>

    </body>

</html>

Fixed testing site you can preview at (but don't copy the whole page code, as it has some server side (cloudflare) stuff in it). http://www.joshlevent.com/dropdownbug/

like image 1
Josh Avatar answered Oct 11 '22 20:10

Josh