使用angular-ui-bootstrap创建可Hoverable popover

时间:2013-11-28 13:54:04

标签: angularjs angularjs-directive angular-ui angular-ui-bootstrap

我有以下代码用于在我的模板文件中创建一个popover:

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

我在popover上有一些可点击的链接。但问题是我无法悬停在创建的弹出窗口上。我提到了链接http://jsfiddle.net/xZxkq/ 并试图创建一个指令即。为此目的的“可见度”。

以下是代码:

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

    }
  }
});

但我得到'element.popover'的例外,因为它未定义。请指出我做错了什么,如何显示/隐藏指令中的角度ui popover。我正在使用angular ui bootstrap JS文件。

10 个答案:

答案 0 :(得分:8)

我不知道这是否与OP有关,但我遇到了同样的问题,幸运的是我设法解决了。

未定义错误

首先,您获得的未定义错误可能是(至少在我的情况下),因为您使用的是ui-bootstrap的开发版本。在我的情况下,我在尝试绑定element.popover时遇到此错误。添加库的缩小版本后,错误就消失了。

将鼠标悬停在悬停上方时保持打开状态

为此,我创建了一个自定义指令,该指令使用popover库中的ui-bootstrap

<强>指令

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

此指令还接受弹出窗口的自定义模板,因此您不仅限于标题和其中的一些文本。您可以创建自己的html模板并将其提供给控件。

<强>用法

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

希望将来帮助其他人:)

修改

根据要求,这是一个Fiddle link。它缺乏造型,但它应该展示它的工作方式。

答案 1 :(得分:5)

我认为Cosmin有可靠的popover,但它似乎确实使用了Twitter Bootstrap popover方法。我们的想法是只使用AngularJS和AngularJS的一个Bootstrap包装器来实现这个可扩展的popover,它是UI BootstrapAngularStrap

所以我把一个只使用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();

                });
            };
        }
    };
});

当你有一个popover元素时,你需要考虑你有触发弹出窗口的元素,你还有元素包含实际的popover内容。

当您将鼠标悬停在具有实际弹出窗口内容的元素上时,我们的想法是保持弹出窗口打开。对于我的指令,链接函数负责触发弹出窗口的元素并附加mouseenter / mouseout事件处理程序。

控制器负责通过AngularStrap $ popover服务设置范围和弹出窗口。控制器在范围上添加AngularStrap服务返回的popover对象,以便在链接函数中可用。它还添加了一个方法attachEventsToPopoverContent,它将mouseenter / mouseout事件附加到带有弹出内容的元素。

该指令的用法如下:

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

答案 2 :(得分:5)

我花了1天时间终于得到了解决方案。

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

请检查 Plunkeer Link 仅检查动态弹出按钮代码

谢谢,

答案 3 :(得分:3)

你必须将触发器放在单引号中,原因是:

<button uib-popover="I appeared on mouse enter!" popover-trigger="'mouseenter'" type="button" class="btn btn-default">Mouseenter</button>

答案 4 :(得分:1)

演示:

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

指令:

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>

答案 5 :(得分:0)

<强> HTML

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

<强>指令

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

        }
    }
});

注意: - 不要忘记在 jQuery.js&amp;之后加入 angular-strap angular.js

答案 6 :(得分:0)

此功能已添加到Angular UI Bootstrap 0.14.0中,并记录在案here。禁用触发器并使用popover-is-open属性手动指示打开/关闭状态。

答案 7 :(得分:0)

我在0.13.X中所做的是将元素设置为<button>,然后设置popover-trigger =“focus”。然后按照您希望的样式设置样式,并通过单击按钮来对焦。您可以将鼠标悬停在popover中并单击链接,我只需要这样做。

答案 8 :(得分:0)

使用uib-popover 进行鼠标事件的最简单方法 请看下面的工作示例! 你不需要 uib-tabset ,我遇到了uib-tabset的问题,所以添加了这个例子。

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

模板: includeFile.html

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

</div>

答案 9 :(得分:0)

我也需要这样做。我在表格单元格中具有一个复选框,该复选框可以具有3种可能的状态:“启用”,“禁用”或“特殊情况”。我要求用户界面规范在框上显示一个弹出框,以显示这些状态或特殊情况下带有链接的句子。

我尝试了其中几种解决方案,其中一种对我有用,它们都添加了额外的代码。经过一番尝试后,我确定我可以添加具有动态值的“ popover-popup-close-delay”属性。所以这对我有用:

<td uib-popover-html="getPopoverTxt()" popover-popup-close-delay="{{ele.isspecial ? 2000 : 300}}" popover-popup-delay="300" popover-append-to-body="true" popover-placement="top" popover-trigger="mouseenter">
    <input id="issynced{{ele.id}}" name="isChecked" type="checkbox" data-ng-checked="ele.ischecked" data-ng-model="ele.ischecked">
    <label for="issynced{{ele.id}}"></label>
</td>

某些上下文:我的表在数据对象数组上循环,因此ele是单个对象。 getPopoverTxt()只是控制器中的一个简单方法,它返回要显示的3个标签之一(“启用”,“禁用”或“带有HTML的特殊文本”)。这里不是必需的,但要点是要使HTML正常工作,您必须将字符串值包装在$ sce.trustAsHtml()中,例如:

var specialText = $sce.trustAsHtml('Text with a link to <a href="/help" target="_blank">contact support</a>');

其余就是我们通常使用的所有常规弹出框和表单输入设置。 “ popover-popup-close-delay”是关键。