web-dev-qa-db-fra.com

Comment fermer le popover de démarrage angulaire en cliquant à l'extérieur

J'essaie de fermer mon Angular-bootstrap popovers en cliquant n'importe où en dehors des popovers. Selon une réponse à cette question, cela peut maintenant être accompli (dans la version 0.13.4) en utilisant le nouveau popover-is-open attribut: Masquer Angular UI Bootstrap popover lorsque vous cliquez en dehors de celui-ci

Actuellement, mon HTML ressemble à ceci:

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

... et mon code de contrôleur pertinent:

vm.togglePopover = false;

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

Cela fonctionne très bien pour ouvrir/fermer le popover en cliquant sur le bouton référencé ci-dessus. Ma question est, comment pourrais-je étendre cette fonctionnalité pour fermer le popover en cliquant n'importe où en dehors du popover? Comment configurer ma gestion d'événements pour y parvenir?

16
MattDionis

Tout d'abord, si vous souhaitez que le popover se ferme sur n'importe quel clic, pas seulement celui à l'extérieur de votre popover, vous pouvez le faire en utilisant le code UI-Bootstrap existant:

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

L'astuce ici est de supprimer le <div> et mettez le popover-trigger="focus" à droite du bouton.


Si vous devez fermer le popover uniquement pour les clics en dehors du contenu du popover, cela sera plus difficile. Vous avez besoin d'une nouvelle directive, comme celle-ci:

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

Ensuite, dans votre modèle popover, utilisez la directive sur l'élément le plus externe:

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

Enfin, dans votre contrôleur, implémentez la fonction closePopover:

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

Ce que nous avons fait ici, c'est:

  • nous écoutons tous les clics sur le document et, si le clic est en dehors de l'élément auquel nous avons ajouté notre close-popover directive:
    • nous invoquons le code ayant la valeur de close-popover
  • nous nettoyons également après nous-mêmes lorsque la portée de la directive est détruite (c'est-à-dire lorsque le popover est fermé) afin de ne plus gérer les clics.

Ce n'est pas la solution la plus propre, car vous devez invoquer la méthode du contrôleur à partir du modèle popover, mais c'est la meilleure que j'ai trouvée.

11
DzinX

Depuis angular-ui 1.0.0, il existe un nouveau déclencheur outsideClick pour les info-bulles et les popovers (introduit dans cette demande de tirage :

<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

Si j'ai bien compris, vous souhaitez que le popover se ferme lorsqu'un utilisateur clique à peu près n'importe où, sauf à l'intérieur du popover lui-même, sauf le bouton de fermeture réel. Cela pourrait être accompli avec un écouteur d'événement:

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

Découvrez ceci plunkr .

Ou, dans votre scénario spécifique:

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

fermez le popover lorsque vous cliquez n'importe où en dehors du popover

Il y a quelque temps, j'ai trouvé cette réponse utile: Comment rejeter un Twitter Bootstrap popover en cliquant à l'extérieur?

Le code que j'ai utilisé dans une de mes démos (mélanger angular et jQueryevent manipulation qui n'est probablement pas recommandée) est spécifique à mes besoins mais peut donner une idée:

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

Je suggère également de regarder la différence entre:

1
Mars Robertson

Vous allez devoir gérer l'événement vous-même comme lorsque vous utilisez le nouveau *-is-open attributs, il n'y a pas de gestion d'événement.

Si vous n'avez pas besoin du contrôle programmatique pour ouvrir/fermer le popover, vous pouvez utiliser le déclencheur focus intégré pour vous donner ce que vous voulez.

1
icfantv