Rohit
Rohit

Reputation: 3136

Trigger function on input blur UNLESS clicking certain link

I can't seem to figure out the logic for this, and hope someone has some advice.

I'm creating a combobox directive, which is simplifying to this:

<div class="combobox" ng-click="$event.stopPropagation()">
    <input type="text" ng-model="search.value" placeholder="System" ng-class="{ resultsOpen: showDropdown }" ng-change="revealDropdown()" ng-focus="revealDropdown()" ng-blur="hideDropdown()">
    <a class="dropdown" ng-click="toggleDropdown($event)"></a>
    <div class="results" ng-show="showDropdown">
        <a ng-repeat="set in data | filter:search" ng-click="setBox($event, set)" ng-bind-html="set.value"></a>
</div>

The link function I've created follows:

link: function (scope, element, attrs) {
    scope.showDropdown = false;
    $combobox = element.children('.combobox');
    $combobox.children('.results').css({ 'top': $combobox.outerHeight(), 'width': $combobox.outerWidth() });
    $combobox.children('.dropdown').css('height', $combobox.outerHeight());

    scope.toggleDropdown = function ($event) {
        $event.stopPropagation();
        scope.showDropdown = scope.showDropdown?false:true;
    };
    scope.revealDropdown = function () {
        if (isNaN(scope.search) || scope.search.length == 0 || $filter('filter')(scope.data, scope.search).length) 
            scope.showDropdown = true;
        else 
            scope.showDropdown = false;
    };
    scope.hideDropdown = function () {
        scope.showDropdown = false;
    };
    $('html').click(function () {
        scope.hideDropdown();
        scope.$apply();
    });

    scope.setBox = function ($event, set) {
        console.log(set);
        scope.search = set;
    };
}

The problem, which became obvious after 30 minutes of fiddling, was that when you click a link in the options, you trigger the blur, causing the link set to close before the links click function triggers.

The only thing I can think to do is create a small timeout which goes off after something like 200ms and if the click hits, unset the timeout, but that's definitely a hacky way of doing it. I was wondering if anyone had a more logical way of doing it.

JSFiddle (though I'm not sure I set it up correctly): http://jsfiddle.net/v7mbrku2/

Upvotes: 2

Views: 1638

Answers (1)

j.wittwer
j.wittwer

Reputation: 9497

Use ng-mousedown instead of ng-click:

<a ng-repeat="set in data" ng-mousedown="setBox($event, set)">

This works because the mousedown event happens before blur, whereas click happens after blur.

Here is a working demo: http://plnkr.co/edit/QG2GcCSkOTcx91wvQzu0?p=preview

Upvotes: 2

Related Questions