RPG
RPG

Reputation: 141

Twitter-Bootstrap dropdownlist open/close event in angularjs

I'm trying to create a drop down list directive, with down-arrow that appears when the mouse is hovering the dropdown header or when the dropdown list is oppend, and disappears otherways.

I succeeded to do this, but if the dropdown list is closed not by selecting element or by pressing on the header list again, than the arrow isn't disappead.

(I.E. If i'm openning one list and than openning another without closing the first one, than arrow of the first list is not disappearing)


JsFiddle - http://jsfiddle.net/rpg2kill/uS4Bs/

code:

var myApp = angular.module('myApp', ['ui.bootstrap']);

function MyCtrl($scope) {
    $scope.supportedList= ['Option1', 'Option2', 'Option3', 'Option4'];
    $scope.selectedItem = 'Option1';
}

myApp.directive('dropDown',

function () {
    return {
            restrict: 'E',
            replace: false,
            scope: {
                supportedList:'=',
                selectedItem:'='
            },
            template:
'<div ng-mouseenter="onMouseEntered()" ng-mouseleave="onMouseLeft()">' + 
    '<a class="dropdown-toggle" data-toggle="dropdown" href="" ng-click="onMouseClicked()" >' +
        '<img ng-style="{\'visibility\': dropDownIconVisibility}"  src="http://png.findicons.com/files/icons/2222/gloss_basic/16/arrow_down.png">  </img>' + //Arrow down Icon
        '<span>{{selectedItem}}</span>' +
    '</a>' +
    '<ul class="dropdown-menu">' +
        '<li ng-repeat="item in supportedList" ng-click="onSelectedItem(item)">' +
            '{{item}}' +
        '</li>' +
    '</ul>' +
'</div>'
        ,
            link: function(scope, element, attrs) {
                scope.dropDownIconVisibility = "hidden";
                scope.dropDownIconVisibilityLocked = false;

                scope.onSelectedItem = function(item) {
                    scope.dropDownIconVisibilityLocked = false;
                    scope.selectedItem = item ;
                };

                scope.onMouseEntered = function()
                {
                    scope.dropDownIconVisibility = "visible";
                };

                scope.onMouseLeft = function()
                {
                    if (scope.dropDownIconVisibilityLocked)
                        return;
                    scope.dropDownIconVisibility = "hidden";
                };

                scope.onMouseClicked = function()
                {
                    scope.dropDownIconVisibility = "visible";
                    scope.dropDownIconVisibilityLocked = !scope.dropDownIconVisibilityLocked;
                };

            }            
    };
})

The code is little ugly. A better solution is to show the arrow if the mouse is hovering OR the list is openned, but I don't know how to bind angular to the state of the dropdown list.

Is there a way to binding angular to Twitter bootstrap's dropdown event? Or is there a better way to solve this problem?

Upvotes: 4

Views: 4224

Answers (3)

RPG
RPG

Reputation: 141

Found CSS solution to the problem. css is so simple instead all the js events..

The CSS:

a.dropdown-toggle img {
    visibility: hidden;
}
li.ng-scope:hover img,li.ng-scope:active img,.open a img{
    visibility: visible;
}

You can check this: http://jsfiddle.net/rpg2kill/HVftB/1/

Upvotes: 2

RPG
RPG

Reputation: 141

I succeeded to solve the problem, unfortunately the solution is not so pretty, but at least it works. I'll try to solve this with only CSS as madhead suggested.

The problem was that I didn't know when the user clicked outside the dropdown, that caused the dropdown popup to close but the icon was still displayed. So I attached an handler to each directive that listen on document.click event and hides the Icon.

    document.addEventListener('click', function (event) {
        scope.$apply(function () {
            scope.hideDropdownIcon();
        });
    }, false);

That worked, but if I clicked on another Dropdown when the current dropdown was opened, the document.click event was not fired. So I had to create my event and attach it to $window and to call it when any dropdown is opens.

var event = new Event('hideDropDownIcon');
$window.addEventListener('hideDropDownIcon', function (e) {
    scope.hideDropdownIcon();
}, false);

You can see it here: http://jsfiddle.net/rpg2kill/uS4Bs/6/

There must be a better solution. So if you know how to do it better or by using only css, I would like to know. Thanks.

Upvotes: 2

madhead
madhead

Reputation: 33412

I suggest you using full CSS approach - it takes less code, it does not trigger JS evaluations, thus, it performs better (Angular is a bit slow with all its cool features). Once you go mobile - CSS will be more preferable, as supports downgrading with media queries and so on... There are too many pros!

Remove all your mouse-tracking code and add just two CSS rules and here you go:

a.dropdown-toggle img {
    visibility: hidden;
}
a.dropdown-toggle:hover img {
    visibility: visible;
}

Upvotes: 2

Related Questions