Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I modify ui.bootstrap.dropdown to respond to a mouse hover over the drop button?

I would like to use the ui.bootstrap.dropdown message box to display text information (not links) in a similar way to the ui.bootstrap.popover. I would like to modify this directive as it does 99% of what I need and I don't want to add all the additional JS that the popover requires.

In other words I would like the "dropdown list area" to display when the user hovers the mouse over the down arrow and then go away when they move the mouse away from the down arrow.

Is there a way that I could add an option to the ui.bootstrap.dropdown so hovering the mouse over the arrow would show and hide the dropdown box. I don't want to place any links in this box.

I hope someone has some ideas that could help me with suggesting how I could change this directive that comes with the ui.bootstrap.dropdown:

.directive('dropdownToggle', function () {
    return {
        require: '?^dropdown',
        link: function (scope, element, attrs, dropdownCtrl) {
            if (!dropdownCtrl) {
                return;
            }

            dropdownCtrl.toggleElement = element;

            var toggleDropdown = function (event) {
                event.preventDefault();

                if (!element.hasClass('disabled') && !attrs.disabled) {
                    scope.$apply(function () {
                        dropdownCtrl.toggle();
                    });
                }
            };

            element.bind('click', toggleDropdown);

            // WAI-ARIA
            element.attr({ 'aria-haspopup': true, 'aria-expanded': false });
            scope.$watch(dropdownCtrl.isOpen, function (isOpen) {
                element.attr('aria-expanded', !!isOpen);
            });

            scope.$on('$destroy', function () {
                element.unbind('click', toggleDropdown);
            });
        }
    };
like image 347
Alan2 Avatar asked Feb 06 '15 11:02

Alan2


3 Answers

This only requires a little extra CSS to accomplish. You didn't provide your markup in the question, so I'm just using the button group examples from the doc. If you provide your specific markup, I'll adjust this answer accordingly.

@import "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css";


.btn-group:hover>.dropdown-menu {
  display: block;
}
<!doctype html>
<html ng-app="ui.bootstrap.demo">

<head>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
  <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.12.0.js"></script>


</head>

<body>

  <div ng-controller="DropdownCtrl">

    <!-- Single button -->
    <div class="btn-group" dropdown is-open="status.isopen">
      <button type="button" class="btn btn-primary dropdown-toggle" dropdown-toggle ng-disabled="disabled">
        Button dropdown <span class="caret"></span>
      </button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a>
        </li>
        <li><a href="#">Another action</a>
        </li>
        <li><a href="#">Something else here</a>
        </li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a>
        </li>
      </ul>
    </div>

    <!-- Split button -->
    <div class="btn-group" dropdown>
      <button type="button" class="btn btn-danger">Action</button>
      <button type="button" class="btn btn-danger dropdown-toggle" dropdown-toggle>
        <span class="caret"></span>
        <span class="sr-only">Split button!</span>
      </button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a>
        </li>
        <li><a href="#">Another action</a>
        </li>
        <li><a href="#">Something else here</a>
        </li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a>
        </li>
      </ul>
    </div>

  </div>
  <script>
    angular.module('ui.bootstrap.demo', ['ui.bootstrap']);
    angular.module('ui.bootstrap.demo').controller('DropdownCtrl', function($scope, $log) {
      $scope.items = [
        'The first choice!',
        'And another choice for you.',
        'but wait! A third!'
      ];

      $scope.status = {
        isopen: false
      };

      $scope.toggled = function(open) {
        $log.log('Dropdown is now: ', open);
      };

      $scope.toggleDropdown = function($event) {
        $event.preventDefault();
        $event.stopPropagation();
        $scope.status.isopen = !$scope.status.isopen;
      };
    });
  </script>
</body>

</html>

Really all that the dropdown does is add an open class to the parent element when it is clicked. The Bootstrap CSS contains a rule that causes the child element with the .dropdown-menu class to be have it's display property set to block:

.open>.dropdown-menu {
  display: block;
}

Therefore, to cause the menu to display when you hover, you can use the :hover pseudo class in CSS to do the same. In this example, I attached the rule to the .btn-group parent element as such:

.btn-group:hover>.dropdown-menu {
  display: block;
}
like image 146
jme11 Avatar answered Oct 05 '22 07:10

jme11


Here's my simple but lo-fi solution. Having the Mouseover and mouseleave on the top level list item was my biggest Eureka, so they act on the group:

 <li uib-dropdown is-open="status.isopen" ng-mouseover="status.isopen = true" ng-mouseleave="status.isopen = false">
                <a ui-sref="abc">ABC</a>
                <ul uib-dropdown-menu role="menu">
                    <li role="menuitem"><a ui-sref="def">DEF</a></li>
                </ul>
            </li>
like image 38
Nathan Marrache Avatar answered Oct 05 '22 05:10

Nathan Marrache


You can decorate directives.

With this way you don't have to touch the original code and you can keep the original behaviour.

HTML

<a href="#" class="open-dropdown-on-hover" dropdown-toggle></a>

JS

angular.module('app').config(uiDropdownToggleDecorate);

uiDropdownToggleDecorate.$inject = ['$provide'];

function uiDropdownToggleDecorate($provide) {
    // the trick here is you have to put 'Directive' after the original directive name
    $provide.decorator('dropdownToggleDirective', uiDropdownToggleDecorator);

    uiDropdownToggleDecorator.$inject = ['$delegate'];

    function uiDropdownToggleDecorator($delegate) {

        var directive = $delegate[0];
        var link = directive.link;

        directive.compile = function() {
            return function(scope, elem, attrs, ctrl) {
                link.apply(this, [scope, elem, attrs, ctrl]);

                function toggle() {
                    if (elem.hasClass('open-dropdown-on-hover')) {
                        scope.$apply(function() {
                            ctrl.toggle();
                        });
                    }
                }

                elem.hover(function() {
                    toggle();
                }, function() {
                    toggle();
                });
            };
        };

        return $delegate;
    }
}
like image 44
cstuncsik Avatar answered Oct 05 '22 05:10

cstuncsik