我想创建一个带有pre标签的bootstrap popover,其中包含一个美化的JSON对象。天真的实施,
<span popover='<pre>{[ some_obj | json:" " ]}</pre>'
popover-trigger='mouseenter'>
在将内容插入弹出窗口之前将其转义。使用html内容指定弹出框体的最佳方法是什么?
答案 0 :(得分:71)
<强>更新强>:
正如this中所见,您现在应该可以在不覆盖默认模板的情况下执行此操作。
<强> ORIGINAL:强>
从角度1.2+ ng-bind-html-unsafe
开始已被删除。您应该使用$sce服务。 Reference
以下是用于创建受信任的html的过滤器。
MyApp.filter('unsafe', ['$sce', function ($sce) {
return function (val) {
return $sce.trustAsHtml(val);
};
}]);
以下是使用此过滤器覆盖的 Angular Bootstrap 0.11.2 模板
// update popover template for binding unsafe html
angular.module("template/popover/popover.html", []).run(["$templateCache", function ($templateCache) {
$templateCache.put("template/popover/popover.html",
"<div class=\"popover {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
" <div class=\"arrow\"></div>\n" +
"\n" +
" <div class=\"popover-inner\">\n" +
" <h3 class=\"popover-title\" ng-bind-html=\"title | unsafe\" ng-show=\"title\"></h3>\n" +
" <div class=\"popover-content\"ng-bind-html=\"content | unsafe\"></div>\n" +
" </div>\n" +
"</div>\n" +
"");
}]);
编辑:这是Plunker实施。
编辑2:由于这个答案不断得到点击,我会尽可能地保持更新。作为参考,Here是angular-ui bootstrap repo中的模板。如果此更改,覆盖模板将需要匹配更新,并添加ng-bind-html=\"title | unsafe\"
和ng-bind-html=\"content | unsafe\"
属性以继续工作。
要更新对话,请检查issue here。
答案 1 :(得分:24)
如果您使用等于或高于 0.13.0 的 angular-ui 版本,则最佳选择是使用popover-template
指令。以下是如何使用它:
<button popover-template="'popover.html'">My HTML popover</button>
<script type="text/ng-template" id="popover.html">
<div>
Popover content
</div>
</script>
注意:请勿忘记popover-template="'popover.html'"
中模板名称周围的引号。
参见 demo plunker
作为旁注,可以将popover模板外部化为专用的html文件,而不是如上所述在<script type="text/ng-template>
元素中声明它。
答案 2 :(得分:9)
我在github项目上发布了一个解决方案:https://github.com/angular-ui/bootstrap/issues/520
我想将此功能添加到您的项目中,这是一个补丁。
添加这些指令:
angular.module("XXX")
.directive("popoverHtmlUnsafePopup", function () {
return {
restrict: "EA",
replace: true,
scope: { title: "@", content: "@", placement: "@", animation: "&", isOpen: "&" },
templateUrl: "template/popover/popover-html-unsafe-popup.html"
};
})
.directive("popoverHtmlUnsafe", [ "$tooltip", function ($tooltip) {
return $tooltip("popoverHtmlUnsafe", "popover", "click");
}]);
并添加模板:
<div class="popover {{placement}}" ng-class="{ in: isOpen(), fade: animation() }">
<div class="arrow"></div>
<div class="popover-inner">
<h3 class="popover-title" ng-bind="title" ng-show="title"></h3>
<div class="popover-content" bind-html-unsafe="content"></div>
</div>
</div>
用法:<button popover-placement="top" popover-html-unsafe="On the <b>Top!</b>" class="btn btn-default">Top</button>
在plunkr上查看:http://plnkr.co/edit/VhYAD04ETQsJ2dY3Uum3?p=preview
答案 3 :(得分:6)
您需要更改默认弹出框模板以指定您要允许Html内容。
查看popover-content
div,它现在已对content
属性进行绑定,允许不安全的html:
angular.module("template/popover/popover.html", []).run(["$templateCache", function ($templateCache) {
$templateCache.put("template/popover/popover.html",
"<div class='popover {{placement}}' ng-class='{ in: isOpen(), fade: animation() }'>" +
"<div class='arrow'></div><div class='popover-inner'>" +
"<h3 class='popover-title' ng-bind='title' ng-show='title'></h3>" +
"<div class='popover-content' ng-bind-html-unsafe='content'></div>" +
"<button class='btn btn-cancel' ng-click='manualHide()'>Cancel</button>" +
"<button class='btn btn-apply' ng-click='manualHide()'>Apply</button></div></div>");
}]);
答案 4 :(得分:5)
对于所有传统的Bootstrap popover
需求,您可以使用以下角度指令。它可以消除HTML模板中的混乱,并且非常易于使用。
您可以配置popover的title
,content
,placement
,淡入/淡出delay
,trigger
事件以及内容是否应该是视为html
。它还可以防止内容溢出和削波。
此处所有代码的相关plunker http://plnkr.co/edit/MOqhJi
Screencap
<强>用法强>
<!-- HTML -->
<div ng-model="popup.content" popup="popup.options">Some element</div>
/* JavaScript */
this.popup = {
content: 'Popup content here',
options: {
title: null,
placement: 'right',
delay: { show: 800, hide: 100 }
}
};
<强>的JavaScript 强>
/**
* Popup, a Bootstrap popover wrapper.
*
* Usage:
* <div ng-model="model" popup="options"></div>
*
* Remarks:
* To prevent content overflow and clipping, use CSS
* .popover { word-wrap: break-word; }
* Popup without title and content will not be shown.
*
* @param {String} ngModel popup content
* @param {Object} options popup options
* @param {String} options.title title
* @param {Boolean} options.html content should be treated as html markup
* @param {String} options.placement placement (top, bottom, left or right)
* @param {String} options.trigger trigger event, default is hover
* @param {Object} options.delay milliseconds or { show:<ms>, hide:<ms> }
*/
app.directive('popup', function() {
return {
restrict: 'A',
require: 'ngModel',
scope: {
ngModel: '=',
options: '=popup'
},
link: function(scope, element) {
scope.$watch('ngModel', function(val) {
element.attr('data-content', val);
});
var options = scope.options || {} ;
var title = options.title || null;
var placement = options.placement || 'right';
var html = options.html || false;
var delay = options.delay ? angular.toJson(options.delay) : null;
var trigger = options.trigger || 'hover';
element.attr('title', title);
element.attr('data-placement', placement);
element.attr('data-html', html);
element.attr('data-delay', delay);
element.popover({ trigger: trigger });
}
};
});
答案 5 :(得分:3)
请参阅https://github.com/jbruni/bootstrap-bower-jbruni,允许使用popover-template
答案 6 :(得分:1)
以下CSS样式似乎已经完成了我想要的特定情况:
.popover-content {
white-space: pre;
font-family: monospace;
}
一般性问题仍然存在。
答案 7 :(得分:0)
这是我的解决方案的fiddle,
此方法的工作方式是,我们实例化页面上popover
数组中将出现的弹出框(请参阅注释中的TODO,以了解如何连接)。
然后,只要用户每次将其切换到或悬停在应触发弹出框的元素上,我们就会在popover
数组中激活该特定弹出框。当用户不再将鼠标悬停在元素上时,我们为数组中的特定popover
设置超时。如果该超时时间已过,它将进行快速检查,以查看用户是否已将鼠标悬停或重新聚焦(通过制表符)。如果是这样,那么我们将使弹出窗口保持活动状态。如果没有,我们将隐藏弹出窗口。
对于CSS,我不想依赖使用引导程序,因此我直接从引导程序中借用了样式。如果尝试使用引导程序的弹出式样式,则在引导程序运行时可能会遇到一些奇怪的行为,这是我们不需要的自定义弹出式窗口上自己的脚本。
HTML:
<section>
<a href="#"
ng-mouseover="showPopover(i)"
ng-mouseleave="hidePopover(i)"
ng-focus="showPopover(i)"
ng-blur="hidePopover(i)">
I trigger a popover - {{i}}
</a>
<popover popover-show="popover[i].popoverTracker">
<div class="arrow"></div>
<div class="custom-popover-content"
ng-mouseover="showPopover(i)"
ng-mouseleave="hidePopover(i)"
ng-focus="showPopover(i)"
ng-blur="hidePopover(i)">
<a href="#"
ng-focus="showPopover(i)"
ng-blur="hidePopover(i)">You can tab into me, I'm accessible!</a>
<br/>
<a href="#"
ng-focus="showPopover(i)"
ng-blur="hidePopover(i)">You can tab into me, I'm accessible!</a>
</div>
</popover>
</section>
角度控制器和指令:
angular.module('controllers', []);
angular.module('directives', []);
angular.module('myApp', ['ngAnimate', 'controllers', 'directives']);
angular.module('controllers')
.controller('MainCtrl', function ($scope, $timeout) {
$scope.popover = [];
(function init() {
// TODO: Make this dynamic so that we can pass it a value and it will generate the right amount
// Initializing the array of popovers on startup
createPopoverTrackers(20);
})();
// Creating an array of popovers equal to the number of popovers on the page
function createPopoverTrackers(count) {
for(var i = 0; i < count; i++) {
$scope.popover.push({
popoverTracker: false,
popoverKeepAlive: false,
timer: null
})
}
}
// A user has focused on an element that has an associated popover
$scope.queueOpenPopover = function(index) {
// Show our specified tracker
$scope.popover[index].popoverTracker = true;
// Hide the rest
Object.keys($scope.popover)
.filter(function(trackerIndex) {
return trackerIndex != index
})
.forEach(function(trackerIndex) {
$scope.popover[trackerIndex].popoverTracker = false;
$scope.popover[trackerIndex].popoverKeepAlive = false;
const timer = $scope.popover[trackerIndex].timer;
if(timer) {
$timeout.cancel(timer);
$scope.popover[trackerIndex].timer = null;
}
})
};
// Queuing up the demise of the popover
$scope.queueKillPopover = function(index) {
$scope.popover[index].timer = $timeout(function() {
if (!$scope.popover[index].popoverKeepAlive) {
// Popover or the popover trigger were not hovered within the time limit, kill it!
$scope.popover[index].popoverTracker = false;
}
}, 700);
};
// When a user focuses into the actual popover itself or it's trigger, we need to keep it alive
$scope.showPopover = function(index) {
$scope.popover[index].popoverKeepAlive = true;
$scope.queueOpenPopover(index);
};
// The user has removed focus from the popover or it's trigger, set this to false so the timer knows to kill it
$scope.hidePopover = function(index) {
$scope.popover[index].popoverKeepAlive = false;
$scope.queueKillPopover(index);
};
});
angular.module('directives')
.directive('popover', function () {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
'popoverShow': '='
},
template: '<div class="custom-popover bottom" ng-show="popoverShow" ng-transclude></div>'
};
});
从引导程序中借用的CSS:
.custom-popover {
position: absolute;
z-index: 1010;
max-width: 276px;
padding: 1px;
text-align: left;
white-space: normal;
background-color: #fff;
border: 1px solid rgba(0,0,0,0.2);
border-radius: 6px;
box-shadow: 0 5px 10px rgba(0,0,0,0.2);
background-clip: padding-box;
}
.custom-popover .arrow,
.custom-popover .arrow:after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
}
.custom-popover .arrow {
border-width: 11px;
}
.custom-popover .arrow:after {
border-width: 10px;
content: "";
}
.custom-popover.bottom {
margin-top: 10px;
}
.custom-popover.bottom .arrow {
top: -11px;
left: 50%;
margin-left: -11px;
border-bottom-color: rgba(0, 0, 0, 0.25);
border-top-width: 0;
}
.custom-popover.bottom .arrow:after {
top: 1px;
margin-left: -10px;
border-bottom-color: #ffffff;
border-top-width: 0;
content: " ";
}
.custom-popover-content {
padding: 9px 14px;
}