Create Hoverable popover using angular-ui-bootstra

2019-01-17 23:35发布

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.

10条回答
劳资没心,怎么记你
2楼-- · 2019-01-18 00:00

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

查看更多
姐就是有狂的资本
3楼-- · 2019-01-18 00:01

Easiest way to have a mouse-event using uib-popover Look at the below working example ! You need not have a uib-tabset, I faced an issue with uib-tabset and so added that example.

<uib-tabset>
      <uib-tab>
        <uib-tab-heading>
          Tab 1
        </uib-tab-heading>
        <div>

          <span ng-mouseover="popoverIsOpen = true" 
                ng-mouseleave="popoverIsOpen = false">
            <button uib-popover-template="'includeFile.html'"
                    popover-trigger="outsideClick" 
                    popover-is-open="popoverIsOpen"
                    popover-placement="right"
                    type="button" class="btn btn-default">
              Dynamic Popover
            </button>
        </span>

        </div>
        <p> tab 1</p>
      </uib-tab>
      <uib-tab>
        <uib-tab-heading>
          Tab 2
        </uib-tab-heading>

        <p> tab 2</p>
      </uib-tab>
    </uib-tabset>

Template: includeFile.html

<div>
  <span>This is for tesitng</span>
  <strong> <a href="www.google.com">www.google.com</a></strong>

</div>
查看更多
ら.Afraid
4楼-- · 2019-01-18 00:05

You have to put the trigger in single quotes, because, reasons:

<button uib-popover="I appeared on mouse enter!" popover-trigger="'mouseenter'" type="button" class="btn btn-default">Mouseenter</button>
查看更多
小情绪 Triste *
5楼-- · 2019-01-18 00:08

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>
查看更多
孤傲高冷的网名
6楼-- · 2019-01-18 00:10

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.

查看更多
爱情/是我丢掉的垃圾
7楼-- · 2019-01-18 00:14

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.

查看更多
登录 后发表回答