Question

I have a bootstrap dropdown menu below. It has a link in it hooked up to a knockout.js binding, that returns false because I don't want the # tag to be sent to the browser URL. However, doing this doesn't close the dropdown menu when I click the link. Any way around this?

HTML

<div class="btn-group">
    <button class="btn dropdown-toggle" data-toggle="dropdown" data-bind="enable: !noResults()"><i class="icon-download-alt" ></i> Export <span class="icon-caret-down"></span></button>

    <ul class="dropdown-menu">
        @foreach(var exportUrl in Model.ExportUrls)
        {
            <li>
                <a href="#" data-bind="disable: noResults(), download: { url: '@exportUrl.Value', data: data }"><img src="/Content/less/images/img/@(exportUrl.Key.ToString().ToLower()).png" alt="@exportUrl.Key.GetDisplayName()"/> @exportUrl.Key.GetDisplayName()</a>
            </li>
        }
    </ul>
</div>

knockut.js binding

ko.bindingHandlers.download = {
    init: function (element, valueAccessor) {

        var value = ko.utils.unwrapObservable(valueAccessor()),
            id = 'download-iframe-container',
            iframe;

        $(element).unbind('click').bind('click', function () {

            iframe = document.getElementById(id);

            if (!iframe) {
                iframe = document.createElement("iframe");
                iframe.id = id;
                iframe.style.display = "none";
            }

            if (value.data) {
                iframe.src = value.url + (value.url.indexOf('?') > 0 ? '&' : '?') + $.param(ko.mapping.toJS(value.data));
            } else {
                iframe.src = value.url;
            }

            document.body.appendChild(iframe);

            return false;
        });
    }
};
Was it helpful?

Solution

Give your links a class (e.g. download):

<a href="#" class="download" data-bind="disable: noResults()....

And your dropdown an id (e.g. dlDropDown):

<button class="btn dropdown-toggle" id="dlDropDown" data-toggle="dropdown" data-bind="enable: !noResults()">

And then add the following event handler:

$("a.download").click(function() {
   $("#dlDropDown").dropdown("toggle");
});

OTHER TIPS

This will actually work with your existing bootstrap markup without having to add any new classes or ids. Hopefully this is helpful to someone else just looking to drop a solution in without changing anything existing.

$(".dropdown-menu a").click(function() {
    $(this).closest(".dropdown-menu").prev().dropdown("toggle");
});

This can be achieved with bootstraps own CSS class dropdown-toggle

Just add that class to your link elements like so: <a class='dropdown-toggle'></a> and it will toggle the dropdown.

I think this will close all dropdowns and expanded navmenus on the page:

$('.in,.open').removeClass('in open');

I unfortunately had no success using .dropdown('toggle') as suggested above...

What did work however was applying bootstrap's dropdown button data attributes to it's own dropdown links:

<button type="button" data-toggle="collapse" data-target=".navbar-collapse" class="navbar-toggle navbar-btn">

...

<ul class="nav navbar-nav">
  <li><a href="#about" class="scroll-to" data-toggle="collapse" data-target=".navbar-collapse">About</a></li>

All I did was add the data-toggle="collapse" and data-target=".navbar-collapse" to each dropdown nav link.

No additional css or js and it worked like a charm :)

Using event.preventDefault() instead of return false does the trick.

Change your code to:

$(element).unbind('click').bind('click', function(e) {
  e.preventDefault();

  // ...

  return true; // or just remove the return clause
});

Simply change the href="#" to href="javscript:void(0);" and then return true in your click event (instead of false).

If you've got an event parameter just do:

$(element).unbind('click').bind('click', function (event)
{
    event.preventDefault();
    return true;
});

A cleaner solution, to keep the dropdown functionality and get what you are looking for.

$("body").on('click', function (e) {
     if (!$(e.target).hasClass("open") && $(e.target).parents(".btn-group.open").length == 0)
         $(this).find(".btn-group.open a").trigger("click");
});

the best answer will be is to perform click so it will act the same as the user click the mouse to hide the drop-down menu, to do this add this snap code to your page:

<script>
    $(document).ready(function () {
        $("li.dropdown ul.dropdown-menu li").click(function (event) {
            event.toElement.parentElement.click();
        })
    })
</script>

you can also add a transparent mask to block any other unwanted click when dropdown is open:

   OnDomReadyHeaderItem.forScript("$('.dropdown').on('shown.bs.dropdown', function (e) { $(this).append('<span id=\"transparent-mask\"></span>')})"));

   OnDomReadyHeaderItem.forScript("$('.dropdown').on('hidden.bs.dropdown', function (e) { $('#transparent-mask').remove()})"));

with the mask:

.dropdown.open #transparent-mask{
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: block;
    margin: auto;
    height: initial;
    z-index: 1000 !important;
}

when click on menu then the nav will be close this is the easy way to do it using jquery onclick="$('#mobile-menu').removeClass('mm-menu_opened');"

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top