44

チェックボックスとフィルターオプションを使用して複数選択ドロップダウンリストを作成しようとしています。外部をクリックしてリストを非表示にしようとしていますが、その方法がわかりませんでした。あなたの助けに感謝。

http://plnkr.co/edit/tw0hLz68O8ueWj7uZ78c

4

9 に答える 9

72

注意してください、ソリューション(質問で提供されたプランカー)は、2番目のポップアップ(複数選択のあるページ)を開くときに、他のボックスのポップアップを閉じません。

ボックスをクリックして新しいポップアップを開くと、クリック イベントは常に停止します。イベントは、開いている他のポップアップに到達することはありません (それらを閉じるため)。

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;
        });
    });
}

私はあなたのプランカーをフォークし、変更を適用しました:

プランカー: 外側をクリックするとポップアップ div を非表示にする

スクリーンショット:

プランカーのスクリーンショット

于 2013-06-27T11:52:27.673 に答える
53

これは古い投稿ですが、これが誰かに役立つ場合は、角度以外に依存しない外側のクリックの実際の例です。

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);
                        });
                    }
               });
           }
        }

    });
于 2015-04-15T22:37:29.583 に答える
8

OK、イベントがAngular Worldの外で発生しているため、$ apply()を呼び出す必要がありました(ドキュメントに従って)。

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

    $document.bind('click', function(){
    scope.isVisible = false;
    scope.$apply();
    });
于 2013-01-29T14:25:38.023 に答える
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);
        });
    }
}])

その後、イベント自体がニュース サービスを介してブロードキャストされます。

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

その後、必要な場所でブロードキャストを聞くことができます。ディレクティブの例を次に示します。

.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();
    }
  }
}])

それが役立つことを願っています!

于 2013-01-29T08:07:47.007 に答える
4

というクールなディレクティブがありangular-click-outsideます。プロジェクトで使用できます。使い方はとても簡単です:

https://github.com/IamAdamJowett/angular-click-outside

于 2015-11-06T10:50:29.890 に答える
4

提供された回答に完全に満足できなかったので、自分で作成しました。改良点:

  • スコープのより防御的な更新。適用/ダイジェストがすでに進行中かどうかを確認します
  • ユーザーがエスケープキーを押すと、divも閉じます
  • div が閉じられると、ウィンドウ イベントのバインドが解除されます (リークを防ぎます)。
  • スコープが破棄されると、ウィンドウ イベントのバインドが解除されます (リークを防ぎます)。

    function link(scope, $element, attributes, $window) {

    var el = $element[0],
        $$window = angular.element($window);
    
    function onClick(event) {
        console.log('window clicked');
    
        // might need to polyfill node.contains
        if (el.contains(event.target)) {
            console.log('click inside element');
            return;
    
        }
    
        scope.isActive = !scope.isActive;
        if (!scope.$$phase) {
            scope.$apply();
        }
    }
    
    function onKeyUp(event) {
    
        if (event.keyCode !== 27) {
            return;
        }
    
        console.log('escape pressed');
    
        scope.isActive = false;
        if (!scope.$$phase) {
            scope.$apply();
        }
    }
    
    function bindCloseHandler() {
        console.log('binding window click event');
        $$window.on('click', onClick);
        $$window.on('keyup', onKeyUp);
    }
    
    function unbindCloseHandler() {
        console.log('unbinding window click event');
        $$window.off('click', onClick);
        $$window.off('keyup', onKeyUp);
    }
    
    scope.$watch('isActive', function(newValue, oldValue) {
        if (newValue) {
            bindCloseHandler();
        } else {
            unbindCloseHandler();
        }
    });
    
    // prevent leaks - destroy handlers when scope is destroyed
    scope.$on('$destroy', function() {
        unbindCloseHandler();
    });
    

    }

リンク機能に$window直接入ります。ただし、取得するためにこれを正確に行う必要はありません$window

function directive($window) {
    return {
        restrict: 'AE',
        link: function(scope, $element, attributes) {
            link.call(null, scope, $element, attributes, $window);
        }
    };
}
于 2014-11-13T22:24:56.743 に答える