Как закрыть Angular -bootstrap popover при нажатии на кнопку

Я пытаюсь закрыть мой Angular -bootstrap popover при нажатии в любом месте вне popovers. Согласно ответу на этот вопрос, теперь это может быть выполнено (в версии 0.13.4) с использованием нового атрибута popover-is-open: Скрыть Angular Попыток пользовательского интерфейса при нажатии за его пределами

В настоящее время мой 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;
};

Это отлично работает для открытия/закрытия popover при нажатии на кнопку, указанную выше. Мой вопрос: как я могу расширить эту функциональность, чтобы закрыть popover, щелкнув где-нибудь за пределами popover? Как мне настроить обработку событий для выполнения этого?

Ответы

Ответ 1

Прежде всего, если вы хотите, чтобы popover закрылся на любом клике, а не только за пределами вашего popover, вы можете сделать это, используя существующий код 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" прямо на кнопку.


Если вам нужно фактически закрыть popover только для кликов вне содержимого popover, тогда это будет сложнее. Вам нужна новая директива, подобная этой:

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

Затем в шаблоне popover используйте директиву для самого внешнего элемента:

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

Наконец, в вашем контроллере реализовайте функцию closePopover:

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

Что мы здесь сделали:

  • мы прослушиваем любые клики по документу и, если щелчок находится за пределами элемента, к которому мы добавили нашу директиву close-popover:
    • мы вызываем любой код, являющийся значением close-popover
  • мы также очищаем себя, когда область действия проекта уничтожается (т.е. когда popover закрывается), чтобы мы больше не обрабатывали клики.

Это не самое чистое решение, так как вы должны вызвать метод контроллера из шаблона popover, но это лучшее, что я придумал.

Ответ 2

Так как angular -ui 1.0.0, появляется новый outsideClick триггер для всплывающих подсказок и popovers (введенных в этот запрос на растяжение:

<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>

Ответ 3

Если я правильно понял, вы хотите, чтобы popover закрывался, когда пользователь щелкает куда угодно, кроме самой внутренней части popover, за исключением кнопки закрытия. Это может быть выполнено с помощью прослушивателя событий:

$('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;
    }
})

Ответ 4

Вам нужно будет обработать событие самостоятельно, как при использовании новых атрибутов *-is-open, обработка событий не будет.

Если вам не нужен программный контроль открытия/закрытия popover, вы можете использовать встроенный триггер focus, чтобы дать вам то, что вы хотите.

Ответ 5

закрыть popover при нажатии в любом месте за пределами popover

Некоторое время назад я нашел этот ответ полезным: Как отклонить загрузку Twitter-бутстрапа, щелкнув внешний вид?

Код, который я использовал в одной из моих демонстраций (смешение angular и jQuery обработки событий, которое, вероятно, не рекомендуется), зависит от моих потребностей, но может дать некоторую идею:

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

Я также предлагаю посмотреть разницу между: