Handling Click-Aways for two or more of the same d

2019-07-19 01:34发布

问题:

I'm attempting to create click-away functionality for an AngularJS directive (ie. when the user doesn't click a certain element, it hides).

I'm adding an event to $(body) which detects a click.

I then check whether either my directive or any of it's children have been clicked. If they haven't, it hides a div.

This works fine when I have one directive, but the moment I add a second of the same kind, it's the second that handles the $(body).click() event. The first doesn't get a look-in.

My code is as follows (I've removed much of it):

angular.module('ma.directives')
    .directive('maDropdownPanel', function () {

        var directiveId = null;

        return {
            restrict: "E",  
            transclude: true,
            templateUrl: "maDropdownPanel.html",
            scope: {},  
            link: function (scope, element, attributes) {

                $('body').on('click', scope.handleClickAway);

                // Get an ID unique to this particular directive.
                directiveId = "ma-dropdown-panel" + scope.$id;    
            },
            controller: function ($scope) {
                $scope.handleClickAway = function (event) {
                    // The following shows which directive took it. Out of two, it's always the second (ie. the last to register the event).
                    console.log(directiveId);
                }
            }
        }
    });

I feel like if I can get the right one to be called, I can handle the rest.

Any help would be appreciated, thanks.

回答1:

I'd suggest that make that directive event to specific click by appending click event name like click.panelClick1 & it would be specific to each element, pass the slug parameter using attribute, but you need change that value each time you make directive

OR

Another good approach would be define that slug parameter for uniqueness of click event by doing something like Math.Random() function which will return random value.

Html

<ma-dropdown-panel slug="1"></ma-dropdown-panel>

Directive

angular.module('ma.directives')
    .directive('maDropdownPanel', function() {

        var directiveId = null;

        return {
            restrict: "E",
            transclude: true,
            templateUrl: "maDropdownPanel.html",
            scope: {},
            link: function(scope, element, attributes) {
                $('body').on('click.panelClick' + attributes.slug, scope.handleClickAway);

                // Get an ID unique to this particular directive.
                directiveId = "ma-dropdown-panel" + scope.$id;
            },
            controller: function($scope) {
                $scope.handleClickAway = function(event) {
                    // The following shows which directive took it. Out of two, it's always the second (ie. the last to register the event).
                    console.log(directiveId);
                }
            }
        }
    });


回答2:

I've found a way to do it. Enzey's comment provided the clue:

Secondly the click event that you are registering needs to be removed at some point or till will exist forever and always be getting evaluated.

The key was to:

  1. Register the click event when the div is shown.
  2. Remove the click event when the div is hidden.

Because a click-away hides the div:

  • There is no chance more than one div will be visible at one time.
  • That means there will only ever be one relevant click event registered at one time.
  • And that means there are no clashes between different click events/directives.

Hope that makes sense.