如何在自定义事件上显示角度引导弹出窗口?

时间:2016-10-13 12:36:30

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

我想在自定义事件上显示bootstrap popover(从服务器加载数据后)。我不明白为什么这段代码不起作用。 JSFiddle

第二个问题,如果设置replace = true,如何触发事件?因为IE8不支持自定义标签并抛出异常。

<div ng-app="tcApp">
    <manual></manual>
</div>
var tcApp = angular.module('tcApp', [ 'ui.bootstrap' ]);

tcApp.config(function ($tooltipProvider) {
    $tooltipProvider.setTriggers({
        'openAfterLoad': 'closeOnClick'
    });
});

tcApp.directive('manual', [ '$timeout', '$interval', function($timeout, $interval) {
    return {
        restrict: 'E',
        scope: {},
        template: 
    '<a ' + 
'   href="#" ' + 
'   ng-if="isManualVisible" ' + 
'   popover-append-to-body="true" ' + 
'   popover-placement="bottom" ' + 
'   popover-trigger="openAfterLoad" ' + 
'   popover-title="{{title}}" ' + 
'   popover="{{content}}" ' + 
'   tooltip="{{title}}" ' + 
'   >' + 
'   <span class="{{textClass}}">' + 
'       <span ng-show="!loading" class="glyphicon glyphicon-question-sign"></span>' + 
'       <span ng-show="loading" class="glyphicon glyphicon-refresh"></span>' + 
'   </span>' + 
'</a>',
        replace: false, // true for IE8 only
        link: function (scope, element, attr) {

            scope.isManualVisible = true;
            scope.title = 'First title value';
            scope.content = 'First content value';
            scope.textClass = 'text-info';

            scope.opened = false;
            scope.loading = false;
            scope.loaded = false;
            scope.loadedTitle = false;
            scope.loadedContent = false;
            scope.checkLoadState = function () {
                if (scope.loadedTitle && scope.loadedContent) {
                    scope.loaded = true;
                    if (scope.loading)
                        scope.loading = false;
                    element.triggerHandler('openAfterLoad');
                }
            };
            scope.$watch('loadedTitle', scope.checkLoadState);
            scope.$watch('loadedContent', scope.checkLoadState);

            element.on('openAfterLoad', function(event) {
                console.log('openAfterLoad');
                scope.opened = true;
            });

            element.on('closeOnClick', function(event) {
                console.log('closeOnClick');
                scope.opened = false;
            });

            element.on('click', function(event) {
                console.log('click');
                if (scope.loaded) {
                    if (scope.opened)
                        element.triggerHandler('closeOnClick');
                    else
                        element.triggerHandler('openAfterLoad');
                } else {
                    scope.loadData();
                }
            });

            scope.loadData = function() {
                if (!scope.loaded && !scope.loading) {
                    scope.loading = true;

                    $interval(function() {
                        scope.title = 'New title value';
                        scope.loadedTitle = true;
                    }, 5000, 1);

                    $interval(function() {
                        scope.content = 'New content value';
                        scope.loadedContent = true;
                    }, 5000, 1);
                }
            };
        }
    };
}]);

1 个答案:

答案 0 :(得分:0)

好的,我找到了解决方案。

首先,在根模板元素上混合replace=trueng-if是一个坏主意。接下来,我将角度/广播事件和原生js事件分开。 popover仍然需要本机事件。

JSFiddle

<div ng-app="tcApp">
    <manual></manual>
</div>
var tcApp = angular.module('tcApp', [ 'ui.bootstrap' ]);

tcApp.config(function ($tooltipProvider) {
    $tooltipProvider.setTriggers({
        'openAfterLoad': 'closeOnClick'
    });
});

tcApp.directive('manual', [ '$timeout', '$interval', function($timeout, $interval) {
    return {
        restrict: 'E',
        scope: {},
        template: 
    '<a ' + 
'   href="#" ' + 
'   ng-show="isManualVisible" ' +
'   ng-click="clickHandler()" ' +
'   popover-append-to-body="true" ' + 
'   popover-placement="bottom" ' + 
'   popover-trigger="openAfterLoad" ' + 
'   popover-title="{{title}}" ' + 
'   popover="{{content}}" ' + 
'   tooltip="{{title}}" ' + 
'   >' + 
'   <span class="{{textClass}}">' + 
'       <span ng-show="!loading" class="glyphicon glyphicon-question-sign"></span>' + 
'       <span ng-show="loading" class="glyphicon glyphicon-refresh"></span>' + 
'   </span>' + 
'</a>',
        replace: true, // true for IE8 only
        link: function (scope, element, attr) {

            scope.isManualVisible = true;
            scope.title = 'First title value';
            scope.content = 'First content value';
            scope.textClass = 'text-info';

            scope.opened = false;
            scope.loading = false;
            scope.loaded = false;
            scope.loadedTitle = false;
            scope.loadedContent = false;
            scope.checkLoadState = function () {
                if (scope.loadedTitle && scope.loadedContent) {
                    scope.loaded = true;
                    if (scope.loading)
                        scope.loading = false;
                    scope.$broadcast('openAfterLoad');
                }
            };
            scope.$watch('loadedTitle', scope.checkLoadState);
            scope.$watch('loadedContent', scope.checkLoadState);

            scope.$on('openAfterLoad', function(event) {
                console.log('openAfterLoad');
                scope.opened = true;
                $timeout(function() {
                    // trigger popover
                    element.triggerHandler('openAfterLoad');
                });
            });

            scope.$on('closeOnClick', function(event) {
                console.log('closeOnClick');
                scope.opened = false;
                $timeout(function() {
                    // trigger popover
                    element.triggerHandler('closeOnClick');
                });
            });

            scope.clickHandler = function(event) {
                console.log('click');
                if (scope.loaded) {
                    if (scope.opened)
                        scope.$broadcast('closeOnClick');
                    else
                        scope.$broadcast('openAfterLoad');
                } else {
                    scope.loadData();
                }
            };

            scope.loadData = function() {
                if (!scope.loaded && !scope.loading) {
                    scope.loading = true;

                    $interval(function() {
                        scope.title = 'New title value';
                        scope.loadedTitle = true;
                    }, 2000, 1);

                    $interval(function() {
                        scope.content = 'New content value';
                        scope.loadedContent = true;
                    }, 3000, 1);
                }
            };
        }
    };
}]);