web-dev-qa-db-ja.com

外部をクリックしたときにAngular-bootstrapポップオーバーを閉じる方法

ポップオーバーの外側をクリックすると、Angular-bootstrap popoversを閉じようとしています。この質問への回答によると、これは新しいpopover-is-open属性: 非表示Angular UI Bootstrap外側をクリックするとポップオーバー

現在、私のHTMLは次のようになっています。

<div
  ng-click="level.openTogglePopover()"
  popover-template="level.changeLevelTemplate"
  popover-trigger="none"
  popover-placement="right"
  popover-is-open="level.togglePopover">
  <button class="btn btn-default btn-xs" type="button">
    <span class="glyphicon glyphicon-sort"></span>
  </button>
</div>

...そして私の関連するコントローラーコード:

vm.togglePopover = false;

vm.openTogglePopover = function() {
  vm.togglePopover = !vm.togglePopover;
};

これは、上記のボタンをクリックしたときにポップオーバーを開いたり閉じたりするのに最適です。私の質問は、ポップオーバーの外側のどこかをクリックしたときにポップオーバーを閉じるようにこの機能を拡張するにはどうすればよいですか?これを実現するためにイベント処理をどのようにセットアップしますか?

16
MattDionis

まず、ポップオーバーをanyクリックで閉じたい場合は、ポップオーバーの外側だけでなく、既存のUI-Bootstrapコードを使用してそれを行うことができます。

<button class="btn btn-default btn-xs" type="button"
        popover-template="level.changeLevelTemplate"
        popover-trigger="focus"
        popover-placement="right">
  <span class="glyphicon glyphicon-sort"></span>
</button>

ここでの秘訣は、周囲の<div>をドロップし、popover-trigger="focus"をボタンの右に配置することです。


ポップオーバーコンテンツの外側のクリックに対してのみ実際にポップオーバーを閉じる必要がある場合は、さらに困難になります。次のような新しいディレクティブが必要です。

app.directive('clickOutside', function ($parse, $timeout) {
  return {
    link: function (scope, element, attrs) {
      function handler(event) {
        if(!$(event.target).closest(element).length) {
          scope.$apply(function () {
            $parse(attrs.clickOutside)(scope);
          });
        }
      }

      $timeout(function () {
        // Timeout is to prevent the click handler from immediately
        // firing upon opening the popover.
        $(document).on("click", handler);
      });
      scope.$on("$destroy", function () {
        $(document).off("click", handler);
      });
    }
  }
});

次に、ポップオーバーテンプレートで、最も外側の要素のディレクティブを使用します。

<div click-outside="level.closePopover()">
   ... (actual popover content goes here)
</div>

最後に、コントローラーにclosePopover関数を実装します。

vm.closePopover = function () {
  vm.togglePopover = false;
};

ここで行ったことは次のとおりです。

  • ドキュメントのクリックをリッスンしています。クリックがclose-popoverディレクティブを追加した要素の外にある場合:
    • close-popoverの値であるコードを呼び出します
  • また、ディレクティブのスコープが破棄されたとき(つまり、ポップオーバーが閉じられたとき)に自分自身をクリーンアップして、クリックを処理しないようにします。

ポップオーバーテンプレート内からコントローラーメソッドを呼び出す必要があるため、これは最もクリーンなソリューションではありませんが、私が思いついた最高のソリューションです。

11
DzinX

Angular-ui 1.0.0以降、ツールチップとポップオーバー用の新しいoutsideClickトリガーがあります( this pull request で導入):

<div
  uib-popover-template="level.changeLevelTemplate"
  popover-trigger="outsideClick"
  popover-placement="right">
  <button class="btn btn-default btn-xs" type="button">
    <span class="glyphicon glyphicon-sort"></span>
  </button>
</div>
13
cdauth

私が正しく理解していれば、ユーザーがポップオーバー自体の内側以外のほとんどの場所をクリックしたときに、実際の閉じるボタンを除いて、ポップオーバーを閉じる必要があります。これは、イベントリスナーで実現できます。

$('html').click(function() {
    if(!$(event.target).is('#foo')) {
        // Code to hide/remove popovers
    }
});

これをチェックしてください plunkr

または、特定のシナリオでは:

$('html').click(function() {
    if(!$(event.target).is('.my-popover-class')) {
        vm.togglePopover = false;
    }
})
2
Tiago

ポップオーバーの外側をクリックすると、ポップオーバーが閉じます

少し前に私はこの答えが役に立ったと感じました: Twitterを閉じる方法Bootstrap外をクリックしてポップオーバー?

私のデモの1つで使用したコードangularjQueryeventの処理の混合は推奨されません)は特定です私のニーズに合わせて、いくつかのアイデアを与えるかもしれません:

  app.directive("eventlistener", function($rootScope) {
    $(window).resize($rootScope.closeAllPopovers); // because Bootstrap popovers don't look good when misplaced

    return {
      link: function(scope, element, attrs) {
        $('body').on('mouseup touchend', $rootScope.closeAllPopovers);
      }
    };
  });

  $rootScope.closeAllPopovers = function (e) {
    $('[data-toggle="popover"]').each(function () {
      if (e) {
        if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
          $(this).popover('hide');
        }
      } else {
        // No event passed - closing all popovers programmatically
        $(this).popover('hide');
      }
    });
  };

また、以下の違いを確認することをお勧めします。

1
Mars Robertson

新しい*-is-open属性を使用する場合、イベント処理は行われないため、イベント処理を自分で行う必要があります。

ポップオーバーの開閉をプログラムで制御する必要がない場合は、組み込みのfocusトリガーを使用して必要なものを提供できます。

1
icfantv