AngularJS ng-repeat在$ compiled指令中多次应用

时间:2014-10-26 21:55:32

标签: javascript angularjs angularjs-directive angularjs-ng-repeat ng-repeat

我编写了一个动态创建元素弹出窗口的指令:

app.directive('popover', function($compile, $timeout){
    return {    
        link: function(scope, element, attrs) {

            $timeout(function() {

                // grab template
                var tpl = $(element).find('.popover-template')

                // grab popover parts of template
                var template = {
                    //$compile( $(element).siblings(".pop-content").contents() )(scope)
                    title: tpl.find('.template-title').contents(),
                    content: tpl.find('.template-content').contents()
                };

                // render template with angular
                var content = $compile(template.content)(scope);
                var title = $compile(template.title)(scope); 

                $(element).popover({
                    html: true,
                    placement: "right",
                    content: content,
                    title: title
                });

                scope.$digest()
            });

        }

    };
});

在应用程序中它看起来像这样:

<span popover>Click me</span>
<div ng-hide="true" class="popover-template">
    <div class="template-title">
        <strong>{{ x.name }} and {{ y.name }}</strong>
    </div>

    <div class="template-content">
        <div>
            <pre>f in [1,2,3]</pre>
            <div ng-repeat="f in [1,2,3]">
                item {{ f }}, index {{ $index }}
            </div>
        </div>
    </div>

</div>

创建并显示弹出窗口。标题也正常工作。但是,在任何迭代中都会多次应用 ng-repeat

enter image description here

如您所见,实际上应该只包含3个元素的迭代包括3 * 3个元素。该指令为3个元素创建了弹出窗口,所以我想这就是我的错误所在。如何确保在每个popover中ng-repeat只被调用一次?

2 个答案:

答案 0 :(得分:0)

问题

由于popover-template元素在引导角度应用程序时(在页面加载时)已经在文档中,因此它已经编译了一次。 ng-repeat元素被3个新元素替换:

<!-- original -->
<div ng-repeat="f in [1,2,3]">item {{ f }}, index {{ $index }}</div>

<!-- replaced -->
<div ng-repeat="f in [1,2,3]">item 1, index 0</div>
<div ng-repeat="f in [1,2,3]">item 2, index 1</div>
<div ng-repeat="f in [1,2,3]">item 3, index 2</div>

当你在链接功能中再次编译它时,每个3 ng重复被触发,制作3个相同的副本,总共9个。

解决方案

将popover-template保存在单独的文件中,以便在页面加载时不编译它。然后,您可以使用$templateCache服务加载它。

通常,只需确保不要多次编译HTML。

答案 1 :(得分:-1)

使用已编译的html作为弹出模板,使用$ http或templateCache加载模板。

HTML:

<span popover>Click me</span>
<script type="text/ng-template" id="popover.html">
  <div class="popover-template">
    <div class="template-title">
      <strong>{{ x.name }} and {{ y.name }}</strong>
    </div>
    <div class="template-content">
      <div>
        <pre>f in [1,2,3] track by $index</pre>
        <div ng-repeat="f in [1,2,3]">
          item {{ f }}, index {{ $index }}
        </div>
      </div>
    </div>
  </div>
</script>

Javascript:

angular.module('app',[]).directive('popover', function($compile, $timeout, $templateCache){
    return {
        link: function(scope, element, attrs) {

            $timeout(function() {
                // grab the template (this is the catch)
                // you can pass the template name as a binding if you want to be loaded dynamically

                var tpl = angular.element($templateCache.get('popover.html'));

                // grab popover parts of template
                var template = {
                    title: tpl.find('.template-title').contents(),
                    content: tpl.find('.template-content').contents()
                };

                // render template with angular
                var content = $compile(template.content)(scope);
                var title = $compile(template.title)(scope); 

                $(element).popover({
                    html: true,
                    placement: "right",
                    content: content,
                    title: title
                });

                scope.$digest()
            });

        }

    };
});

另外,我用一个工作示例制作了这个羽毛球:http://embed.plnkr.co/IoIG1Y1DT8RO4tQydXnX/