Join the Stack Overflow Community
Stack Overflow is a community of 6.4 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

I have the following code for creating a popover in my template file:

<span class="icon-globe visibility" 
      id="visibilityFor{{post.metaData.assetId}}" 
      popover="{{post.visibilityListStr}}" 
      popover-placement="right" 
      popover-trigger="mouseenter" 
      popover-popup-delay="50" 
      visibility>
</span>

I have a few clickable links on the popover. But the problem is I'm not able to hover on the popover created. I referred to the link http://jsfiddle.net/xZxkq/ and tried to create a directive viz. 'visibility' for this purpose.

Here is the code:

myAppModule.directive("visibility", function ($timeout,$rootScope) {
  return {

    controller: function ($scope, $element) {
        $scope.attachEvents = function (element) {
            $('.popover').on('mouseenter', function () {
                $rootScope.insidePopover = true;
            });
            $('.popover').on('mouseleave', function () {
                $rootScope.insidePopover = false;
                $(element).popover('hide');
            });
        }
    },
    link: function (scope, element, attrs) {
        $rootScope.insidePopover = false;

        element.bind('mouseenter', function (e) {
            $timeout(function () {
                if (!$rootScope.insidePopover) {
                    element.popover('show');
                    attachEvents(element);
                }
            }, 200);
        });

        element.bind('mouseout', function (e) {
            $timeout(function () {
                if (!$rootScope.insidePopover) {
                    element.popover('show');
                    attachEvents(element);
                }
            }, 200);
        });

    }
  }
});

But I get an exception for 'element.popover' since it is undefined. Please point as to what I'm doing wrong and how can I show/hide the angular ui popover from the directive. I am using angular ui bootstrap JS file.

share|improve this question

I don't know if this is relevant to the OP anymore, but I've had the same problem and fortunately I managed to solve it.

Undefined error

First thing first, the undefined error you are getting might be (at least in my case) because you are using the development version of ui-bootstrap. In my case I got this error when trying to bind element.popover. After adding the minified version of the library the error went away.

Keep the popover open when hovering over it

To do this I have created a custom directive that makes use of the popover from the ui-bootstrap library.

Directive

app.directive('hoverPopover', function ($compile, $templateCache, $timeout, $rootScope) {
var getTemplate = function (contentType) {
    return $templateCache.get('popoverTemplate.html');
};
return {
    restrict: 'A',
    link: function (scope, element, attrs) {
        var content = getTemplate();
        $rootScope.insidePopover = false;
        $(element).popover({
            content: content,
            placement: 'top',
            html: true
        });
        $(element).bind('mouseenter', function (e) {
            $timeout(function () {
                if (!$rootScope.insidePopover) {
                    $(element).popover('show');
                    scope.attachEvents(element);
                }
            }, 200);
        });
        $(element).bind('mouseleave', function (e) {
            $timeout(function () {
                if (!$rootScope.insidePopover)
                    $(element).popover('hide');
            }, 400);
        });
    },
    controller: function ($scope, $element) {
        $scope.attachEvents = function (element) {
            $('.popover').on('mouseenter', function () {
                $rootScope.insidePopover = true;
            });
            $('.popover').on('mouseleave', function () {
                $rootScope.insidePopover = false;
                $(element).popover('hide');
            });
        }
    }
};
});

This directive also accepts a custom template for the popover, so you are not limited to just title and some text in it. You can create your own html template and feed it to the control.

Usage

<a href="#" hover-popover>Click here</a>

Hopes this helps someone else in the future :)

Edit

As requested, here is a Fiddle link. It lacks the styling, but it should demonstrate the way it works.

share|improve this answer
    
will you please host it on fiddle? – Laxmikant Dange Mar 5 '15 at 7:38
    
@Laxmikant Dange I've added a fiddle link in the answer – Cosmin Ionascu Mar 5 '15 at 8:08

I think Cosmin has the hoverable popover right, but it does seem to be using the Twitter Bootstrap popover method. The idea is to have this hoverable popover implemented only with AngularJS and one of the Bootstrap wrappers for AngularJS, which are UI Bootstrap or AngularStrap.

So I have put together an implementation which uses only AngularStrap:

myApp.directive('hoverablePopover', function ($rootScope, $timeout, $popover) {
    return {
        restrict: "A",
        link: function (scope, element, attrs) {

            element.bind('mouseenter', function (e) {
                $timeout(function () {
                    if (!scope.insidePopover) {

                        scope.popover.show();
                        scope.attachEventsToPopoverContent();
                    }
                }, 200);
            });

            element.bind('mouseout', function (e) {
                $timeout(function () {
                    if (!scope.insidePopover) {

                        scope.popover.hide();
                    }
                }, 400);
            });

        },
        controller: function ($scope, $element, $attrs) {

            //The $attrs will server as the options to the $popover.
            //We also need to pass the scope so that scope expressions are supported in the  popover attributes
            //like title and content.
            $attrs.scope = $scope;
            var popover = $popover($element, $attrs);
            $scope.popover = popover;
            $scope.insidePopover = false;

            $scope.attachEventsToPopoverContent = function () {

                $($scope.popover.$element).on('mouseenter', function () {

                    $scope.insidePopover = true;

                });
                $($scope.popover.$element).on('mouseleave', function () {

                    $scope.insidePopover = false;
                    $scope.popover.hide();

                });
            };
        }
    };
});

When you have a popover element, you need to take into account that you have the element that triggers the popover and you also have the element with the actual popover content.

The idea is to keep the popover open when you mouse over the element with the actual popover content. In the case of my directive, the link function takes care of the element that triggers the popover and attaches the mouseenter/mouseout event handlers.

The controller takes care of setting the scope and the popover itself via the AngularStrap $popover service. The controller adds the popover object returned by the AngularStrap service on the scope so that it is available in the link function. It also adds a method attachEventsToPopoverContent, which attaches the mouseenter/mouseout events to the element with the popover content.

The usage of this directive is like this:

  <a title="Popover Title" data-placement="left" data-trigger="manual" data-content="{{someScopeObject}}" content-template="idOfTemplateInTemplateCache" hoverablePopover="">
share|improve this answer

There I spend 1 day and finally get solution.

<button uib-popover="{{dynamicPopover.content}}" 
    popover-trigger="outsideClick" popover-is-open="popoverIsOpen"
    ng-mouseenter="popoverIsOpen = !popoverIsOpen" 
    popover-title="{{dynamicPopover.title}}" type="button" class="btn btn-default">Dynamic Popover</button>

Please check Plunkeer Link Check only Dynamic Popover button code

Thanks,

share|improve this answer

demo:

https://jsbin.com/fuwarekeza/1/edit?html,output

directive:

myAppModule.directive('popoverHoverable', ['$timeout', '$document', function ($timeout, $document) {
    return {
        restrict: 'A',
        scope: {
            popoverHoverable: '=',
            popoverIsOpen: '='
        },
        link: function(scope, element, attrs) {
            scope.insidePopover = false;

            scope.$watch('insidePopover', function (insidePopover) {
                togglePopover(insidePopover);
            })

            scope.$watch('popoverIsOpen', function (popoverIsOpen) {
                scope.insidePopover = popoverIsOpen;
            })

            function togglePopover (isInsidePopover) {
                $timeout.cancel(togglePopover.$timer);
                togglePopover.$timer = $timeout(function () {
                    if (isInsidePopover) {
                        showPopover();
                    } else {
                        hidePopover();
                    }
                }, 100)
            }

            function showPopover () {
                if (scope.popoverIsOpen) {
                    return;
                }

                $(element[0]).click();
            }

            function hidePopover () {
                scope.popoverIsOpen = false;
            }

            $(document).bind('mouseover', function (e) {
                var target = e.target;
                if (inside(target)) {
                    scope.insidePopover = true;
                    scope.$digest();
                }
            })

            $(document).bind('mouseout', function (e) {
                var target = e.target;
                if (inside(target)) {
                    scope.insidePopover = false;
                    scope.$digest();
                }
            })

            scope.$on('$destroy', function () {
                $(document).unbind('mouseenter');
                $(document).unbind('mouseout');
            })

            function inside (target) {
                return insideTrigger(target) || insidePopover(target);
            }

            function insideTrigger (target) {
                return element[0].contains(target);
            }

            function insidePopover (target) {
                var isIn = false;
                var popovers = $('.popover-inner');
                for (var i = 0, len = popovers.length; i < len; i++) {
                    if (popovers[i].contains(target)) {
                        isIn = true;
                        break;
                    }
                }
                return isIn;
            }
        }
    }
}]);

html:

<span class="icon-globe visibility" 
      id="visibilityFor{{post.metaData.assetId}}" 
      popover="{{post.visibilityListStr}}" 
      popover-is-open="{{post.$open}}"
      popover-trigger="click" 
      popover-hoverable="true"
      visibility>
</span>
share|improve this answer
    
That should be marked as the right answer. – Phillipe Gustavo Aug 20 at 12:34

html

 <span class="icon-globe" id="visibilityFor" popover="hello how are you" 
       popover-placement="right" popover-trigger="mouseenter" 
       popover-popup-delay="50" viz>
</span>

directive

myAppModule.directive('viz', function ($rootScope,$timeout){
    return{

        restrict:"A",
        link: function (scope, element, attrs) {
            $rootScope.insidePopover = false;

            element.bind('mouseenter', function (e) {
                $timeout(function () {
                    if (!$rootScope.insidePopover) {
                        element.popover('show');
                     //  attachEvents(element);
                    }
                }, 200);
            });

            element.bind('mouseout', function (e) {
                $timeout(function () {
                    if (!$rootScope.insidePopover) {
                        element.popover('show');
                     //   attachEvents(element);
                    }
                }, 200);
            });

        }
    }
});

Note : - Don't forget to include angular-strap after jQuery.js & angular.js

share|improve this answer
    
Still gives the same error. "Object doesn't support property or method 'popover'" – Adarsh Konchady Nov 29 '13 at 5:13
    
It is tested by me and run fine with me So check your other javascript code and file. or Make fiddle of your code and let me check it. – Nishchit Dhanani Nov 29 '13 at 9:08
3  
You are on about a COMPLETELY different library. This question is for Angular-UI Bootstrap, you answered it for Angular-Strap. – Siyfion Jun 9 '14 at 9:36

This feature was added in Angular UI Bootstrap 0.14.0 and is documented here. Disable the triggers and use the popover-is-open property to manually dictate the opened/closed state.

share|improve this answer

What I did that gets my by in 0.13.X is to set the element to be hoverable to a <button> and then set the popover-trigger="focus". Then style the button how you wish, and focus the button by clicking it. You can hover in the popover and click a link, all I need to do.

share|improve this answer

I have solved it in a very cleaned way and thought to share it: .popover is being created not as a child of the uib-popover so the idea is to wrap uib-popover with a parent and to control show&hide on hovering the parent. .popover and uib-popover are children of this parent so just left to set popover-trigger=none and you have what you are wishing for.

I created a plunk example: https://plnkr.co/edit/6vzrrH1KUyQeLHDz1hWp?p=preview

<span ng-init="popoverOpened=false" ng-mouseover="popoverOpened=true" ng-mouseleave="popoverOpened=false">
    <button class="btn btn-default" uib-popover-html="htmlPopover" 
            popover-trigger="none" popover-placement="bottom-left" popover-is-open="popoverOpened" >
       <span>hover me</span>
    </button>
</span>

enjoy.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.