【问题标题】:Create Hoverable popover using angular-ui-bootstrap使用 angular-ui-bootstrap 创建 Hoverable popover
【发布时间】:2013-11-28 13:54:04
【问题描述】:

我有以下代码用于在我的模板文件中创建弹出框:

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

我在弹出框上有一些可点击的链接。但问题是我无法将鼠标悬停在创建的弹出框上。我参考了链接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 弹出框。我正在使用 angular ui bootstrap JS 文件。

【问题讨论】:

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


【解决方案1】:

我已经以非常干净的方式解决了它并想分享它:

.popover 不是作为 uib-popover 的子级创建的 所以这个想法是用父级包装 uib-popover 并在悬停父级时控制显示和隐藏。

.popoveruib-popover 是此父级的子级 所以只需设置 popover-trigger=none 就可以得到你想要的。

我创建了一个plunk example

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

享受吧。

【讨论】:

  • 我尝试了该页面中的几乎所有解决方案,这是最好的。
  • 虽然这不是最优雅的解决方案,但它最终对我来说是最容易实现的。感谢分享!
  • 警告:它不适用于 popover-append-to-body="true"
  • 它正在使用 popover-append-to-body="true" 只需添加 popover-class。我让它在我的应用程序中运行。
  • @oded 很抱歉在这么长时间后重新打开它,但是您能否详细说明添加 popover-class 将如何使这项工作与附加到正文一起工作?干杯
【解决方案2】:

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

未定义错误

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

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

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

指令

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。它缺少样式,但应该展示它的工作方式。

【讨论】:

  • 请把它放在 fiddle 上好吗?
  • @Laxmikant Dange 我在答案中添加了一个小提琴链接
  • 也许你应该注意这个解决方案需要 JQuery
  • @tatsuhirosatou 考虑到这是我们正在谈论的 Angular 1.x,我想这应该不是问题,因为 Angular 需要运行 jQuery。
  • @CosminIonascu Angular 不需要运行 jQuery,许多人竭尽全力避免将 jQuery 作为其代码的依赖项。 docs.angularjs.org/misc/faq
【解决方案3】:

在那里我花了 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 只检查动态弹出框按钮代码

谢谢,

【讨论】:

  • 这适用于 popover-append-to-body="true",与其他答案不同。但我需要为这个 popover-trigger="'outsideClick'" 更改这个 popover-trigger="outsideClick" (双引号内的简单引号)非常感谢!
【解决方案4】:

我认为 Cosmin 具有可悬停弹出框的权利,但它似乎确实使用了 Twitter Bootstrap 弹出框方法。我们的想法是让这个可悬停的弹出框仅使用 AngularJS 和 AngularJS 的引导包装器之一实现,它们是 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();

                });
            };
        }
    };
});

当您有一个弹出框元素时,您需要考虑到您拥有触发弹出框的元素,并且您还拥有带有实际弹出框内容的元素。

这个想法是当您将鼠标悬停在具有实际弹出框内容的元素上时保持弹出框打开。在我的指令的情况下,链接函数负责触发弹出窗口并附加 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="">

【讨论】:

    【解决方案5】:

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

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

    【讨论】:

    • 这是正确的答案。谢谢
    【解决方案6】:

    演示:

    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>
    

    【讨论】:

    • 这将如何与多个弹出框一起工作?无法为每个变量创建单独的变量以保持打开/关闭状态
    【解决方案7】:

    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 & angular.js 之后包含 angular-strap

    【讨论】:

    • 仍然给出同样的错误。 “对象不支持属性或方法‘popover’”
    • 它已经过我的测试并且运行良好所以检查你的其他javascript代码和文件。或者修改你的代码,让我检查一下。
    • 你在一个完全不同的图书馆。这个问题是针对 Angular-UI Bootstrap 的,你是针对 Angular-Strap 回答的。
    【解决方案8】:

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

    【讨论】:

      【解决方案9】:

      我在 0.13.X 中所做的就是将元素设置为可悬停到 &lt;button&gt;,然后设置 popover-trigger="focus"。然后按照您的意愿设置按钮样式,并通过单击来聚焦按钮。您可以将鼠标悬停在弹出窗口中并单击一个链接,我需要做的就是。

      【讨论】:

        【解决方案10】:

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

        【讨论】:

        【解决方案11】:

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

        我尝试了其中的几种解决方案,其中一种对我有用,而且它们都添加了额外的代码。在玩了一些之后,我确定我可以添加具有动态值的“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”是关键。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-10-24
          • 2015-04-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-24
          • 1970-01-01
          相关资源
          最近更新 更多