89

I'd like to use a Twitter Bootstrap dropdown button:

    <div class="btn-group">
      <button class="btn dropdown-toggle" data-toggle="dropdown">Action <span class="caret"></span></button>
      <ul class="dropdown-menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
      </ul>
    </div><!-- /btn-group -->

When the user changes the value of the button to 'Another action', instead of simply navigating to #, I'd actually like to handle the action in a custom way.

But I can't see any event handlers in the dropdown plugin for doing this.

Is it actually possible to use Bootstrap dropdown buttons to handle user actions? I'm starting to wonder if they're only intended for navigation - it's confusing that the example gives a list of actions.

Richard
  • 62,943
  • 126
  • 334
  • 542
  • 1
    Wouldn't a function that is triggered onclick of the anchor tag work? – Cameron Chapman Aug 16 '12 at 14:20
  • First of these are not any buttons these are anchors. You can take a look at the event handlers by inspecting the bootstrap.js file. But as far as I know all of these actions are processed with jQuery so it should not be a big deal do edit or override this functionality. – mas-designs Aug 16 '12 at 14:21

8 Answers8

79

Twitter bootstrap is meant to give a baseline functionality, and provides only basic javascript plugins that do something on screen. Any additional content or functionality, you'll have to do yourself.

<div class="btn-group">
  <button class="btn dropdown-toggle" data-toggle="dropdown">Action <span class="caret"></span></button>
  <ul class="dropdown-menu">
    <li><a href="#" id="action-1">Action</a></li>
    <li><a href="#" id="action-2">Another action</a></li>
    <li><a href="#" id="action-3">Something else here</a></li>
  </ul>
</div><!-- /btn-group -->

and then with jQuery

jQuery("#action-1").click(function(e){
//do something
e.preventDefault();
});
Thomas Jones
  • 4,892
  • 26
  • 34
  • 3
    Tried that, however, getting no event fired off. I can catch the event of clicking a button though. What else might be in the way? – Wrench Jul 12 '13 at 09:44
  • 1
    @RonnieKilsbo not sure. This solution does work as stated, and I have used it countless times. You might not be setting your anchor's id correctly, or you might be binding before the elements exist - I highly recommend using [jQuery's on](http://api.jquery.com/on/) in this case. – Thomas Jones Jul 12 '13 at 15:36
  • 1
    You are correct, my bad. I had inserted elements in the DOM after I bind the clickables with jQuery, which is a bad thing. :) Working, confirmed. – Wrench Jul 12 '13 at 18:17
18

Try this:

$('div.btn-group ul.dropdown-menu li a').click(function (e) {
    var $div = $(this).parent().parent().parent(); 
    var $btn = $div.find('button');
    $btn.html($(this).text() + ' <span class="caret"></span>');
    $div.removeClass('open');
    e.preventDefault();
    return false;
});
Fernando
  • 2,123
  • 4
  • 17
  • 21
14

In Bootstrap 3 'dropdown.js' provides us with the various events that are triggered.

click.bs.dropdown
show.bs.dropdown
shown.bs.dropdown

etc

Stevanicus
  • 7,561
  • 9
  • 49
  • 70
  • 1
    That's true, but you still don't work within the bootstrap framework to attach event handlers. You do that on your own. Bootstrap has *always* been about doing things on the screen, not providing custom functionality. It's assumed that the dev will be able to hook up their own dropdown events. – Thomas Jones Jul 22 '15 at 12:38
8

Here is a working example of how you could implement custom functions for your anchors.

http://jsfiddle.net/CH2NZ/43/

You can attach an id to your anchor:

<li><a id="alertMe" href="#">Action</a></li>

And then use jQuery's click event listener to listen for the click action and fire you function:

$('#alertMe').click(function(e) {
    alert('alerted');
    e.preventDefault();// prevent the default anchor functionality
});
Cameron Chapman
  • 796
  • 9
  • 19
4

I have been looking at this. On populating the drop down anchors, I have given them a class and data attributes, so when needing to do an action you can do:

<li><a class="dropDownListItem" data-name="Fred Smith" href="#">Fred</a></li>

and then in the jQuery doing something like:

$('.dropDownListItem').click(function(e) {
    var name = e.currentTarget;
    console.log(name.getAttribute("data-name"));
});

So if you have dynamically generated list items in your dropdown and need to use the data that isn't just the text value of the item, you can use the data attributes when creating the dropdown listitem and then just give each item with the class the event, rather than referring to the id's of each item and generating a click event.

Andrew Berry
  • 853
  • 3
  • 10
  • 25
3

Anyone here looking for Knockout JS integration.

Given the following HTML (Standard Bootstrap dropdown button):

<div class="dropdown">
    <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
        Select an item               
        <span class="caret"></span>
    </button>
    <ul class="dropdown-menu" role="menu">
        <li>
            <a href="javascript:;" data-bind="click: clickTest">Click 1</a>
        </li>
        <li>
            <a href="javascript:;" data-bind="click: clickTest">Click 2</a>
        </li>
        <li>
            <a href="javascript:;" data-bind="click: clickTest">Click 3</a>
        </li>
    </ul>
</div>

Use the following JS:

var viewModel = function(){
    var self = this;

    self.clickTest = function(){
        alert("I've been clicked!");
    }  
};

For those looking to generate dropdown options based on knockout observable array, the code would look something like:

var viewModel = function(){
    var self = this;

    self.dropdownOptions = ko.observableArray([
        { id: 1, label: "Click 1" },
        { id: 2, label: "Click 2" },
        { id: 3, label: "Click 3" }
    ])

    self.clickTest = function(item){
        alert("Item with id:" + item.id + " was clicked!");
    }  
};

<!-- REST OF DD CODE -->
<ul class="dropdown-menu" role="menu">
    <!-- ko foreach: { data: dropdownOptions, as: 'option' } -->
    <li>
        <a href="javascript:;" data-bind="click: $parent.clickTest, text: option.clickTest"></a>
    </li>
    <!-- /ko -->
</ul>
<!-- REST OF DD CODE -->

Note, that the observable array item is implicitly passed into the click function handler for use in the view model code.

pim
  • 12,019
  • 6
  • 66
  • 69
3

Without having to change your button group at all, you can do the following. Below, I assume your dropdown button has an id of fldCategory.

<script type="text/javascript">

$(document).ready(function(){

  $('#fldCategory').parent().find('UL LI A').click(function (e) {
    var sVal = e.currentTarget.text;
    $('#fldCategory').html(sVal + ' <span class="caret"></span>');
    console.log(sVal);
  });

});

</script>

Now, if you set the .btn-group of this item itself to have the id of fldCategory, that's actually more efficient jQuery and runs a little faster:

<script type="text/javascript">

$(document).ready(function(){

  $('#fldCategory UL LI A').click(function (e) {
    var sVal = e.currentTarget.text;
    $('#fldCategory BUTTON').html(sVal + ' <span class="caret"></span>');
    console.log(sVal);
  });

});

</script>
Volomike
  • 23,743
  • 21
  • 113
  • 209
0

Here you go, options have values, label and css classes that gets reflected on parent element upon selection.

$(document).on('click','.update_app_status', function (e) {
            let $div = $(this).parent().parent(); 
            let $btn = $div.find('.vBtnMain');
            let $btn2 = $div.find('.vBtnArrow');
            let cssClass = $(this).data('status_class');
            let status_value = $(this).data('status_value');
            let status_label = $(this).data('status_label');
            $btn.html(status_label);
            $btn.removeClass();
            $btn2.removeClass();
            $btn.addClass('btn btn-sm vBtnMain '+cssClass);
            $btn2.addClass('btn btn-sm vBtnArrow dropdown-toggle dropdown-toggle-split '+cssClass);
            $div.removeClass('show');
            $div.find('.dropdown-menu').removeClass('show');
            e.preventDefault();
            return false;
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" rel="stylesheet"/>


  

   <div class="btn-group">
   <button type="button" class="btn btn-sm vBtnMain btn-warning">Awaiting Review</button>
   <button type="button" class="btn btn-sm vBtnArrow btn-warning dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
       <span class="sr-only">Toggle Dropdown</span>
   </button>
   <div class="dropdown-menu dropdown-menu-right">
     <a class="dropdown-item update_app_status" data-status_class="btn-warning" data-status_value="1" data-status_label="Awaiting Review" href="#">Awaiting Review</a>
     <a class="dropdown-item update_app_status" data-status_class="btn-info" data-status_value="2" data-status_label="Reviewed" href="#">Reviewed</a>
     <a class="dropdown-item update_app_status" data-status_class="btn-dark" data-status_value="3" data-status_label="Contacting" href="#">Contacting</a>
     <a class="dropdown-item update_app_status" data-status_class="btn-success" data-status_value="4" data-status_label="Hired" href="#">Hired</a>
     <a class="dropdown-item update_app_status" data-status_class="btn-danger" data-status_value="5" data-status_label="Rejected" href="#">Rejected</a>
   </div>
   </div>
Himanshu Saini
  • 702
  • 11
  • 25