单击外部时隐藏AngularJS下拉指令

Ami*_*ava 44 angularjs

我正在尝试使用复选框和过滤器选项创建多选下拉列表.我试图隐藏列表,我点击外面,但无法弄清楚如何.感谢您的帮助.

http://plnkr.co/edit/tw0hLz68O8ueWj7uZ78c

che*_*eym 68

请注意,您的解决方案(问题中提供的Plunker)在打开第二个弹出窗口时(在具有多个选择的页面上)不会关闭其他框的弹出窗口.

通过单击框以打开新弹出窗口,将始终停止单击事件.该事件永远不会到达任何其他打开的弹出窗口(关闭它们).

我通过删除event.stopPropagation();行并匹配弹出窗口的所有子元素来解决这个问题.

如果events元素与弹出窗口的任何子元素都不匹配,则只会关闭弹出窗口.

我将指令代码更改为以下内容:

select.html(指令代码)

link: function(scope, element, attr){

    scope.isPopupVisible = false;

    scope.toggleSelect = function(){
        scope.isPopupVisible = !scope.isPopupVisible;
    }

    $(document).bind('click', function(event){
        var isClickedElementChildOfPopup = element
            .find(event.target)
            .length > 0;

        if (isClickedElementChildOfPopup)
            return;

        scope.$apply(function(){
            scope.isPopupVisible = false;
        });
    });
}
Run Code Online (Sandbox Code Playgroud)

我分叉你的plunker并应用了这些变化:

Plunker:点击外面隐藏弹出式div

截图:

Plunker截图

  • **性能提示:**如果您在页面上分配了这些选择框,则只应在弹出窗口为_opened_时绑定"click"并在弹出窗口为_closed_时解除绑定"click". (15认同)
  • @BhoomtawathPlinsut `element[0].contains(event.target)`。https://developer.mozilla.org/en-US/docs/Web/API/Node/contains (3认同)
  • 没有jQuery怎么做?没有jQuery,element.find仅限于标签名称. (2认同)

Dan*_*ker 50

这是一个旧帖子,但如果这有助于这里的任何人是一个单击外部的工作示例,不依赖于角度以外的任何东西.

module('clickOutside', []).directive('clickOutside', function ($document) {

        return {
           restrict: 'A',
           scope: {
               clickOutside: '&'
           },
           link: function (scope, el, attr) {

               $document.on('click', function (e) {
                   if (el !== e.target && !el[0].contains(e.target)) {
                        scope.$apply(function () {
                            scope.$eval(scope.clickOutside);
                        });
                    }
               });
           }
        }

    });
Run Code Online (Sandbox Code Playgroud)

  • 我认为当范围被破坏时我们需要关闭监听器. (7认同)
  • 奇迹般有效.但是,我建议将`scope.$ apply`和`scope.$ eval`更改为`scope.applyAsync`和`scope.evalAsync`,以获得更好的性能. (2认同)

Ami*_*ava 8

好的,我必须调用$ apply(),因为事件发生在角度世界之外(根据doc).

    element.bind('click', function(event) {
    event.stopPropagation();      
    });

    $document.bind('click', function(){
    scope.isVisible = false;
    scope.$apply();
    });
Run Code Online (Sandbox Code Playgroud)


F L*_*has 7

我通过监听全局点击事件来实现它:

.directive('globalEvents', ['News', function(News) {
    // Used for global events
    return function(scope, element) {
        // Listens for a mouse click
        // Need to close drop down menus
        element.bind('click', function(e) {
            News.setClick(e.target);
        });
    }
}])
Run Code Online (Sandbox Code Playgroud)

然后通过新闻服务广播该事件本身

angular.factory('News', ['$rootScope', function($rootScope) {
    var news = {};
    news.setClick = function( target ) {
        this.clickTarget = target;
        $rootScope.$broadcast('click');
    };
}]);
Run Code Online (Sandbox Code Playgroud)

然后,您可以随时随地收听广播.这是一个示例指令:

.directive('dropdown', ['News', function(News) {
  // Drop down menu für the logo button
  return {
    restrict: 'E',
    scope: {},
    link: function(scope, element) {
      var opened = true;
      // Toggles the visibility of the drop down menu
      scope.toggle = function() {
        element.removeClass(opened ? 'closed' : 'opened');
        element.addClass(opened ? 'opened' : 'closed');
      };
      // Listens for the global click event broad-casted by the News service
      scope.$on('click', function() {
        if (element.find(News.clickTarget.tagName)[0] !== News.clickTarget) {
          scope.toggle(false);
        }
      });
      // Init
      scope.toggle();
    }
  }
}])
Run Code Online (Sandbox Code Playgroud)

我希望它有所帮助!