我正在尝试使用带有静态但复杂内容的Bootstrap popover(通过ui-bootstrap)。
popover本身可行 - 直接将其应用于特定元素会导致它按预期显示:
<div data-popover="test"></div>
使用范围内的基本动态内容也有效:
<div data-popover="{{key}}"></div>
但是我想以更复杂的方式生成内容,涉及角度服务(尽管它是全局的 - 没有涉及ajax或其他异步代码)。这有效:
<div data-popover="{{getPopoverText(key)}}"></div>
但它会导致每个摘要都进行调用,而在我的情况下,我知道一旦找到该值就永远不会改变。 (遗憾的是我使用的是AngularJS 1.2.23,它早于一次性绑定支持,因此我无法使用它。)
所以我尝试用指令做到这一点:
<div data-generate-popover="key"></div>
module.directive('generatePopover', ['myService', function(myService) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var key = scope.$eval(attrs.generatePopover);
var content = myService.getPopoverText(key);
element.removeAttr('data-generate-popover');
element.attr('data-popover', content);
},
};
}]);
这确实可以正确运行并交换属性,data-popover
属性包含要显示的正确内容。然而,弹出窗口不会出现(可能是AngularJS没有注意到我添加了指令)。
我的最新尝试(受this question启发)是在更改元素后重新编译元素:
module.directive('generatePopover',
['myService', '$compile',
function(myService, $compile) {
return {
restrict: 'A',
priority: 10000,
link: {
pre: function (scope, element, attrs) {
var key = scope.$eval(attrs.generatePopover);
var content = myService.getPopoverText(key);
element.removeAttr('data-generate-popover');
element.attr('data-popover', content);
$compile(element)(scope);
}
},
};
}]);
这似乎按预期工作。我的问题是:这是正确的做法,是否有任何负面影响?除了升级以获得一次性绑定支持之外,还有更好的方法吗?
编辑:显然,一个负面后果是,如果元素具有其他复杂指令(特别是ngRepeat
;可能还有ngIf
),则此额外编译无法正常工作等等,但我没有测试过。)
答案 0 :(得分:0)
这里的问题是,弹出窗口的自动初始化只会在dom ready事件中发生一次,之后所做的任何更改都不会初始化插件。
因此,尝试初始化自己的插件
module.directive('generatePopover', ['myService', function (myService) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var key = scope.$eval(attrs.generatePopover);
var content = myService.getPopoverText(key);
element.removeAttr('data-generate-popover');
//set the popover content here
element.attr('data-content', content);
//here initialize the
element.popover();
},
};
}]);
答案 1 :(得分:0)
你不应该担心角度会在每个消化周期中执行所有观察者,否则你永远不会担心。即使是像{{key}}
这样的简单绑定实际上也是一个在每个摘要周期中解析scope.key
的函数。实际上,每个消化周期甚至会做很多次。
Angular是如何工作的(至少在1.3之前,这将完全改变角度2),并且它已经很好地优化了:你唯一关心的应该是制作函数{{1}尽可能快:这里严格禁止jQuery!
现在,如果真的希望这样做,那么您的方法似乎是正确的方法。如果您仍希望getPopoverText
更新,但仅当您决定而不是每个摘要周期时,您可以添加
key
并在每次需要时播放此事件。但同样,一个典型的角度应用程序可以拥有数千名观察者,并且如果观察者本身编码良好,仍然可以表现得非常流畅,所以我强烈建议不要浪费时间并将代码复杂化为其中一个,而是专注于拥有一个尽可能简单的scope.$on('popover.update', updateThePopover);
方法。只是我自己经验的建议。
PS:为了降低执行的观察者数量,尝试在许多独立的指令中对应用程序进行模块化,并且更喜欢getPopoverText
而不是scope.$digest
来消化孤立的范围而不是所有这些范围。
答案 2 :(得分:0)
自从发布这个问题以来,我已经简化了一些事情(尽管有一点点处理,我并不完全满意):
<div data-generate-popover="key" data-popover="{{tooltip}}"></div>
module.directive('generatePopover', ['myService', function(myService) {
return {
restrict: 'A',
priority: 10,
link: function (scope, element, attrs) {
var key = scope.$eval(attrs.generatePopover);
element.removeAttr(attrs.$attr.generatePopover);
scope.tooltip = myService.getPopoverText(key);
},
};
}]);
(在这种情况下,我知道每个范围中只有一个被ngRepeat
定义为更高,所以我不需要担心多个tooltip
被覆盖。)
话虽如此,这仍然是一个黑客,我期待在我升级AngularJS时用一次性绑定替换它。