bryan
bryan

Reputation: 9399

Hide Angular UI Bootstrap popover when clicking outside of it

I am trying to manually close a bootstrap popover to get it to close when I click anywhere on the document or body that isn't the popover.

The closest thing I have found to accomplishing this is to create a directive (found this answer) but this is for a manual trigger if a variable is true or false.

Could anyone help me figure out how to to get it to close if I click on anything that isn't the popover?

I don't mind using jQuery $(document).click(function(e){}); I just have no clue how to call a close.

<div id="new_button" popover-template="plusButtonURL" popover-placement="right" popover-append-to-body="true" popover-animation="false">+</div>

Normally popover-trigger="focus" would do the trick, however my popover contains content that needs to be clicked on. I have an ng-click inside my popover that get's ignored if I use the focus trigger so I am looking for a not-so-conventional way to get around that.

Upvotes: 49

Views: 53363

Answers (12)

ajin
ajin

Reputation: 1206

popover-trigger="'outsideClick'" This will work perfectly.

popover-trigger="outsideClick" This will not.

I took 1 day to sort it out why it was not working for me.

It is because they checking this using this code, "if (trigger === 'outsideClick')"

This is due to strong type check where we need to pass it as String

Upvotes: 16

Tejashree Patil
Tejashree Patil

Reputation: 1

1) Use ng-bootstrap for Popover.

2) Update the ng-bootstrap version to 3.0.0 or above. i.e npm install --save @ng-bootstrap/[email protected]

3) After updating, you may use [autoClose] functionality of Ngbpopover.

<button type="button" class="btn btn-outline-secondary" popoverTitle="Pop title" [autoClose]="true" ngbPopover="Click anywhere or press Escape to close (try the toggling element too)">Click to toggle</button>

4) Hope it helps !

Upvotes: 0

ArunBabuVijayanath
ArunBabuVijayanath

Reputation: 510

What about the 'outsideClick' option in the '$uibTooltipProvider' setTriggers method. Documentation says "The outsideClick trigger will cause the tooltip to toggle on click, and hide when anything else is clicked." Documentation

Upvotes: 2

npn
npn

Reputation: 113

Add onclick="void(0)" behavior to some of your background elements which when tapped will get rid of the popovers.

Have a look at https://github.com/angular-ui/bootstrap/issues/2123

Upvotes: 0

cdauth
cdauth

Reputation: 7597

Since Angular UI Bootstrap 1.0.0, there is a new outsideClick trigger for tooltips and popovers (introduced in this pull request. In Angular UI Bootstrap 2.0.0, the popover-trigger has been modified to use angular expressions (Changelog), so the value has to be put in quotes. This code will work with current versions of angular-ui:

<div id="new_button" uib-popover-template="plusButtonURL" popover-trigger="'outsideClick'"
    popover-placement="right" popover-append-to-body="true" popover-animation="false">+</div>

This code will work with old versions of Angular UI Bootstrap (before 2.0.0):

<div id="new_button" uib-popover-template="plusButtonURL" popover-trigger="outsideClick"
    popover-placement="right" popover-append-to-body="true" popover-animation="false">+</div>

Upvotes: 30

Jake Scott
Jake Scott

Reputation: 31

I had the same issue and popover-trigger="'outsideClick'" worked for me. Interesting that the documentation did not state this issue.

Upvotes: 3

Ratheesh Naithalath
Ratheesh Naithalath

Reputation: 89

What you are looking for is

<button
      popover-trigger="outsideClick" 
      class="btn btn-default">
   Right
</button>

From the documentation - The outsideClick trigger will cause the popover to toggle on click, and hide when anything else is clicked.

Upvotes: 8

Avinash Dalvi
Avinash Dalvi

Reputation: 9301

Angular boostrap ui new version 1.x having facility to out side click function. upgrade it to new version.

<button uib-popover-template="updatePassword.templateUrl" popover-title="Update Password" popover-trigger="outsideClick" popover-placement="right" popover-append-to-body="true">Click here</button>

its work for me.

focus will not work if any submit button or click event in popover. so this useful way to do.

Upvotes: 1

Prasad Shigwan
Prasad Shigwan

Reputation: 552

You can use:

Markup

<div ng-app="Module">
    <div ng-controller="formController">
        <button uib-popover-template="dynamicPopover.templateUrl" popover-trigger="focus" 
          popover-placement="left" type="button" class="btn btn-default">
             Popover With Template
        </button>

        <script type="text/ng-template" id="myPopoverTemplate.html">
            <div>
                <span>prasad!!</span>
            </div>
        </script>
    </div>
</div>

Javascript

<script type="text/javascript">
    var app = angular.module("Module", ['ui.bootstrap']);
    app.controller("formController", ['$scope', function($scope) {
        $scope.dynamicPopover = {
            templateUrl: 'myPopoverTemplate.html'
        };
    }]);
</script>

Upvotes: 5

icfantv
icfantv

Reputation: 4643

UPDATE: With the 1.0 release, we've added a new trigger called outsideClick that will automatically close the popover or tooltip when the user clicks outside the popover or tooltip.

Starting with the 0.14.0 release, we've added the ability to programmatically control when your tooltip/popover is open or closed via the tooltip-is-open or popover-is-open attributes.

Upvotes: 42

jme11
jme11

Reputation: 17387

EDITED:

Plunker Demo

Here's how it works (the still long and exhaustive explanation):

  1. Create a custom directive that allows you to target the trigger element.
  2. Create a custom directive that is added to the body and will find the trigger element and fire the custom event when it is clicked.

Create a custom directive to target the trigger element:

You need to trigger the custom event handler from the element that opened the popover (in the demo this is the button). The challenge is that the popover is appended as a sibling to this element and I always think that things have greater potential to break when you are traversing the DOM and expecting it to have a specific structure. There are several ways you can target the trigger element, but my approach is to add a unique classname to the element (I choose 'trigger') when you click on it. Only one popover can be opened at a time in this scenario, so it's safe to use a classname, but you can modify to suit your preference.

Custom Directive

app.directive('popoverElem', function(){
  return{
    link: function(scope, element, attrs) {
      element.on('click', function(){
        element.addClass('trigger');
      });
    }
  }
});

Applied to button

<button popover-template="dynamicPopover.templateUrl" popover-title="{{dynamicPopover.title}}" class="btn btn-default" popover-elem>Popover With Template</button>

Create a custom directive for the document body (or any other element) to trigger the popover close:

The last piece is to create a custom directive that will locate the triggering element and fire the custom event to close the popover when the element it is applied to is clicked. Of course, you have to exclude the initial click event from the 'trigger' element, and any elements you want to interact with on the inside of your popover. Therefore, I added an attribute called exclude-class so you can define a class that you can add to elements whose click events should be ignored (not causing the popover to close).

To clean things up, when the event handler is triggered, we remove the trigger class that was added to the trigger element.

app.directive('popoverClose', function($timeout){
  return{
    scope: {
      excludeClass: '@'
    },
    link: function(scope, element, attrs) {
      var trigger = document.getElementsByClassName('trigger');

      function closeTrigger(i) {
        $timeout(function(){ 
          angular.element(trigger[0]).triggerHandler('click').removeClass('trigger'); 
        });
      }

      element.on('click', function(event){
        var etarget = angular.element(event.target);
        var tlength = trigger.length;
        if(!etarget.hasClass('trigger') && !etarget.hasClass(scope.excludeClass)) {
          for(var i=0; i<tlength; i++) {
            closeTrigger(i)
          }
        }
      });
    }
  };
});

I added this to the body tag so that the entire page* acts as a dismissible backdrop for the popover:

<body popover-close exclude-class="exclude">

And, I added the exclude class to the input in the popover:

<input type="text" ng-model="dynamicPopover.title" class="form-control exclude">

So, there are some tweaks and gotchas, but I'll leave that to you:

  1. You should set a default exclude class in the link function of the popover-close directive, in case one is not defined.
  2. You need to be aware that the popover-close directive is element bound, so if you remove the styles I set on the html and body elements to give them 100% height, you could have 'dead areas' within your viewport if your content doesn't fill it.

Tested in Chrome, Firefox and Safari.

Upvotes: 24

Patrick Motard
Patrick Motard

Reputation: 2660

There is a property called popover-trigger that you can assign the property focus to.

<button 
      popover-placement="right" 
      popover="On the Right!" 
      popover-trigger="focus" 
      class="btn btn-default">
   Right
</button>

This does the trick! :)

Edit: To allow for the tooltip to be clicked on and not trigger focus lost, consider an approach similar to this

If you want it to work in angular, try creating your own trigger definition. Suggestions on how to do that can be found here.

Upvotes: 13

Related Questions