基于表达式使用angular动态打开/关闭弹出窗口(或工具提示)的好方法?

dan*_*wig 28 popover twitter-bootstrap angularjs angular-ui-bootstrap angular-strap

我有一个连接到角度的表单,使用它进行验证.我能够使用ng-show指令显示错误消息,如下所示:

<span ng-show="t3.f.needsAttention(f.fieldName)" ng-cloak>
    <span ng-show="f.fieldName.$error.required && !f.fieldName.$viewValue">
        This field is required.
    </span>
</span>
Run Code Online (Sandbox Code Playgroud)

.. f表单在哪里,t3来自表单上的自定义指令,用于检测是否尝试提交,并包含用于检查字段有效性的函数.

我想要完成的是在popover中显示验证消息.无论是bootstrap的原生popover,还是来自UI Bootstrap的popover ,我都加载了.我也可以考虑AngularStrap,如果使用该lib更容易.

我现在正在努力的是一般的弹出窗口的性质 - 它们基于点击,鼠标中心,模糊等用户事件自动显示.我想要做的是显示和隐藏基于相同的弹出窗口上面的ng-show属性中的函数.因此,当表达式返回false时隐藏它,当它返回true时,显示它.

我知道bootstrap有这个.popover('show'),但是我不应该告诉有关dom的任何角度,所以我不确定如何访问$(element).popover()if在自定义表单控制器功能中执行此操作.我错过了什么吗?

更新

重复投票中提到的解决方案仍然只显示mouseenter上的popover.我想强制它显示,好像在做$('#popover_id').popover('show').

小智 29

您还可以构建自己的扩展触发器.这将适用于Tooltip和Popover.

首先扩展Tooltip触发器,如下所示:

// define additional triggers on Tooltip and Popover
app.config(['$tooltipProvider', function($tooltipProvider){
    $tooltipProvider.setTriggers({
        'show': 'hide'
    });
}]);
Run Code Online (Sandbox Code Playgroud)

然后在HTML标记上定义触发器,如下所示:

<div id="RegisterHelp" popover-trigger="show" popover-placement="left" popover="{{ 'Login or register here'}}">
Run Code Online (Sandbox Code Playgroud)

现在你可以用JavaScript调用hide和show,这是一个3秒钟的节目.

$("#RegisterHelp").trigger('show');
//Close the info again
$timeout(function () {
    $("#RegisterHelp").trigger('hide');
}, 3000);
Run Code Online (Sandbox Code Playgroud)

  • 我不明白这一点:`{show:hide}` - 那是做什么的? (6认同)
  • @chovy,该位正在注册将显示/隐藏工具提示/弹出窗口的新事件映射.如果你看看源代码,有一个`triggerMap`,它将`mouseenter`与`mouseleave`,`click`与`click`放在一起,`focus`与`blur`默认.此对象中的关键是要监听以显示popover/toolip的事件,值是要侦听以隐藏popover/tooltip的事件. (3认同)
  • 这被打破了:https://github.com/angular-ui/bootstrap/commit/7556beda486f26b40fb860448316e8a32457e9e9 (3认同)
  • 你能举个小提琴吗?当我扩展触发器时,我的弹出窗口不显示.. (2认同)

dan*_*wig 20

事实证明,用自定义指令装饰ui-bootstrap工具提示或popover并不是很困难.这是用typescript编写的,但它的javascript部分应该是显而易见的.这段代码用于装饰工具提示或弹出窗口:

'use strict';

module App.Directives.TooltipToggle {

    export interface DirectiveSettings {
        directiveName: string;
        directive: any[];
        directiveConfig?: any[];
    }

    export function directiveSettings(tooltipOrPopover = 'tooltip'): DirectiveSettings {

        var directiveName = tooltipOrPopover;

        // events to handle show & hide of the tooltip or popover
        var showEvent = 'show-' + directiveName;
        var hideEvent = 'hide-' + directiveName;

        // set up custom triggers
        var directiveConfig = ['$tooltipProvider', ($tooltipProvider: ng.ui.bootstrap.ITooltipProvider): void => {
            var trigger = {};
            trigger[showEvent] = hideEvent;
            $tooltipProvider.setTriggers(trigger);
        }];

        var directiveFactory = (): any[] => {
            return ['$timeout', ($timeout: ng.ITimeoutService): ng.IDirective => {
                var d: ng.IDirective = {
                    name: directiveName,
                    restrict: 'A',
                    link: (scope: ng.IScope, element: JQuery, attr: ng.IAttributes) => {

                        if (angular.isUndefined(attr[directiveName + 'Toggle'])) return;

                        // set the trigger to the custom show trigger
                        attr[directiveName + 'Trigger'] = showEvent;

                        // redraw the popover when responsive UI moves its source
                        var redrawPromise: ng.IPromise<void>;
                        $(window).on('resize', (): void => {
                            if (redrawPromise) $timeout.cancel(redrawPromise);
                            redrawPromise = $timeout((): void => {
                                if (!scope['tt_isOpen']) return;
                                element.triggerHandler(hideEvent);
                                element.triggerHandler(showEvent);

                            }, 100);
                        });

                        scope.$watch(attr[directiveName + 'Toggle'], (value: boolean): void => {
                            if (value && !scope['tt_isOpen']) {
                                // tooltip provider will call scope.$apply, so need to get out of this digest cycle first
                                $timeout((): void => {
                                    element.triggerHandler(showEvent);
                                });
                            }
                            else if (!value && scope['tt_isOpen']) {
                                $timeout((): void => {
                                    element.triggerHandler(hideEvent);
                                });
                            }
                        });
                    }
                };
                return d;
            }];
        };

        var directive = directiveFactory();

        var directiveSettings: DirectiveSettings = {
            directiveName: directiveName,
            directive: directive,
            directiveConfig: directiveConfig,
        };

        return directiveSettings;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用这一段代码,您可以设置程序化隐藏和显示工具提示或弹出窗口,如下所示:

var tooltipToggle = App.Directives.TooltipToggle.directiveSettings();
var popoverToggle = App.Directives.TooltipToggle.directiveSettings('popover');
var myModule = angular.module('my-mod', ['ui.bootstrap.popover', 'ui.bootstrap.tpls'])
    .directive(tooltipToggle.directiveName, tooltipToggle.directive)
        .config(tooltipToggle.directiveConfig)
    .directive(popoverToggle.directiveName, popoverToggle.directive)
        .config(popoverToggle.directiveConfig);
Run Code Online (Sandbox Code Playgroud)

用法:

<span tooltip="This field is required."
    tooltip-toggle="formName.fieldName.$error.required"
    tooltip-animation="false" tooltip-placement="right"></span>
Run Code Online (Sandbox Code Playgroud)

要么

<span popover="This field is required."
    popover-toggle="formName.fieldName.$error.required"
    popover-animation="false" popover-placement="right"></span>
Run Code Online (Sandbox Code Playgroud)

因此,我们正在重用ui-bootstrap工具提示或弹出窗口附带的所有其他内容,并且只实现该-toggle属性.装饰指令监视属性,并触发显示或隐藏的自定义事件,然后由ui-bootstrap工具提示提供程序处理.

更新:

由于这个答案似乎对其他人有帮助,这里的代码是用javascript写的(上面的打字稿或多或少都编译成了这个javascript):

'use strict';

function directiveSettings(tooltipOrPopover) {

    if (typeof tooltipOrPopover === "undefined") {
        tooltipOrPopover = 'tooltip';
    }

    var directiveName = tooltipOrPopover;

    // events to handle show & hide of the tooltip or popover
    var showEvent = 'show-' + directiveName;
    var hideEvent = 'hide-' + directiveName;

    // set up custom triggers
    var directiveConfig = ['$tooltipProvider', function ($tooltipProvider) {
        var trigger = {};
        trigger[showEvent] = hideEvent;
        $tooltipProvider.setTriggers(trigger);
    }];

    var directiveFactory = function() {
        return ['$timeout', function($timeout) {
            var d = {
                name: directiveName,
                restrict: 'A',
                link: function(scope, element, attr) {
                    if (angular.isUndefined(attr[directiveName + 'Toggle']))
                        return;

                    // set the trigger to the custom show trigger
                    attr[directiveName + 'Trigger'] = showEvent;

                    // redraw the popover when responsive UI moves its source
                    var redrawPromise;
                    $(window).on('resize', function() {
                        if (redrawPromise) $timeout.cancel(redrawPromise);
                        redrawPromise = $timeout(function() {
                            if (!scope['tt_isOpen']) return;
                            element.triggerHandler(hideEvent);
                            element.triggerHandler(showEvent);

                        }, 100);
                    });

                    scope.$watch(attr[directiveName + 'Toggle'], function(value) {
                        if (value && !scope['tt_isOpen']) {
                            // tooltip provider will call scope.$apply, so need to get out of this digest cycle first
                            $timeout(function() {
                                element.triggerHandler(showEvent);
                            });
                        }
                        else if (!value && scope['tt_isOpen']) {
                            $timeout(function() {
                                element.triggerHandler(hideEvent);
                            });
                        }
                    });
                }
            };
            return d;
        }];
    };

    var directive = directiveFactory();

    var directiveSettings = {
        directiveName: directiveName,
        directive: directive,
        directiveConfig: directiveConfig,
    };

    return directiveSettings;
}
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢这个非常优雅的解决方案,只会破坏角度ui的私密性. (2认同)
  • @PetrPeller javascript提供. (2认同)

Pet*_*ler 17

适用于ui.bootstrap0.13.4及更高版本:

popover-is-open引入了一个新参数()来控制官方仓库中的popovers ui.bootstrap.这是您在最新版本中使用它的方式:

<a uib-popover="Hello world!" popover-is-open="isOpen" ng-click="isOpen = !isOpen">
   Click me to show the popover!
</a>
Run Code Online (Sandbox Code Playgroud)

对于ui.bootstrap0.13.3及更早版本:

我刚刚发布了一个小指令,可以在GitHub上添加对弹出窗口的更多控制:https:
//github.com/Elijen/angular-popover-toggle

您可以使用范围变量来显示/隐藏popover使用popover-toggle="variable"指令,如下所示:

<span popover="Hello world!" popover-toggle="isOpen">
   Popover here
</span>
Run Code Online (Sandbox Code Playgroud)

这是一个演示Plunkr:http://plnkr.co/edit/QeQqqEJAu1dCuDtSvomD?p =preview


小智 5

我的方法:

  • 跟踪模型中弹出窗口的状态
  • 使用适当的指令更改每个元素的状态。

想法是将DOM操作留给指令。

我整理了一个小提琴,希望可以提供更好的解释,但是您会在提到的UI Bootstrap中找到更复杂的解决方案。

jsfiddle

标记:

<div ng-repeat="element in elements" class="element">

    <!-- Only want to show a popup if the element has an error and is being hovered -->
    <div class="popover" ng-show="element.hovered && element.error" ng-style>Popover</div>

    <div class="popoverable" ng-mouseEnter="popoverShow(element)" ng-mouseLeave="popoverHide(element)">
        {{ element.name }}
    </div>

</div>
Run Code Online (Sandbox Code Playgroud)

JS:

function DemoCtrl($scope)
{

    $scope.elements = [
        {name: 'Element1 (Error)', error: true, hovered: false},
        {name: 'Element2 (no error)', error: false, hovered: false},
        {name: 'Element3 (Error)', error: true, hovered: false},
        {name: 'Element4 (no error)', error: false, hovered: false},
        {name: 'Element5 (Error)', error: true, hovered: false},
    ];

    $scope.popoverShow = function(element)
    {
        element.hovered = true;
    }

    $scope.popoverHide = function(element)
    {
        element.hovered = false
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 我认为这种方法有一些优点,并且效果很好,但是使用组件来做到这一点将更加简洁,灵活和可重用。 (2认同)