如何在自定义指令中处理 ng-repeat 子元素?

Posted

技术标签:

【中文标题】如何在自定义指令中处理 ng-repeat 子元素?【英文标题】:How can I get a handle on ng-repeat children elements in my custom directive? 【发布时间】:2013-07-26 19:28:07 【问题描述】:

我正在尝试构建一个自定义指令,将其内容重新排列为网格。 我想嵌入 ng-repeat 指令的结果,然后重新排序结果元素。

问题是当我在链接函数中调用element.children() 方法时,我有一个空数组,因为ng-repeat 指令尚未呈现并被解释为注释。

否则,如果指令的内容是“静态”,则该指令效果很好。

html

<grid n='6'>
    <div ng-repeat="i in [1,2,3]"></div>
</grid>

我的指令只有有趣的代码片段:

app.directive('grid', [function () 
    return 

        restrict: 'E',
        replace: true,
        transclude: true,
        template: "<div ng-transclude></div>",

        link: function (scope, grid, attrs) 

            // With an ngRepeat transcluded, els result in an empty array
            var els = grid.children();

            // ...
    ; 
]);

我错过了什么?

【问题讨论】:

在你的链接函数中你可以尝试使用 $timout(function() //access grid children,0); 确实有效,但是这种方法可靠吗? 实际上你的子模板是在发布链接功能之后渲染的,所以你需要添加$timout,它会工作,因为它会引入一些延迟。 嘿@Laurent 我的建议能以任何方式帮助你吗?请分享您的发现 @scniro:感谢您抽出宝贵时间回复。大约两年前我发布了这个问题,所以我现在继续前进,但是我相信你的回答会对其他遇到它的人有用! 【参考方案1】:

要实现重新排序,您有多种选择:

    操作 DOM。恕我直言,这是最不受欢迎的方式,它不是很棱角分明。 在您的链接函数中重新排序 ngRepeat 中使用的数组 ([1, 2, 3])。 使用orderBy过滤器(doc)

我创建了一个 plunk 来演示 2 和 3,希望它可以提供帮助。 http://plnkr.co/edit/vrgeBoJZiG6WMu4Rk46u?p=preview

【讨论】:

我可能用“重新订购”一词误导了您。我的目标更多是将元素重新排列为网格(例如 3 个元素/行)。无论如何谢谢你;)【参考方案2】:

有几种方法可以解决这个问题。您将看到的最简单和最常见的解决方案是 cmets 建议的 - 像这样利用 $timeout...

.directive('grid', ['$timeout', function ($timeout) 
    return 
        restrict: 'E',
        replace: true,
        transclude: true,
        template: '<div ng-transclude></div>',
        link: function (scope, grid, attrs) 
            $timeout(function() 
                console.log(grid.children());
            );
        
    
]);

$timeout([fn], [delay], [invokeApply], [Pass]);

[...]

invokeApply - 如果设置为 false 则跳过模型脏检查,否则将在 $apply 块中调用 fn。 (默认:true

调用 $timeout 将强制执行 $digest 循环 - 因此,当您记录子项时 - ng-repeat 指令将“完成”。与ng-repeat 的竞争是这里问题的症结所在——因为当我们进入link 函数时,它仍在发挥作用。


您可以解决此问题的另一种方法 - 这当然不太常见 - 但在说明更详细的事件序列方面做得很好,如下...

.directive('grid', [function () 
    return 
        restrict: 'E',
        replace: true,
        transclude: true,
        template: '<div ng-transclude></div>',
        link: function (scope, grid, attrs) 
            scope.$on('repeat-done', function () 
                console.log(grid.children());
            );
        
    
])
.directive('ngRepeat', [function () 
    return 
        restrict: 'A',
        link: function (scope, elem, attrs) 
            if (scope.$last)
                scope.$root.$broadcast('repeat-done');
        
    ;
]);

在这里,我们悄悄地扩展 ng-repeat 以在完成时调用一个函数 - 我们可以通过 $on 在我们的 link 函数中订阅它。


JSFiddle Link - 展示这两种方法的简单演示

【讨论】:

以上是关于如何在自定义指令中处理 ng-repeat 子元素?的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS:如何使用自定义指令来取代ng-repeat

Angular 自定义指令在 ng-repeat 中使用 if 条件

如何使用 ControlValueAccessor Angular 在自定义输入中使用指令

如何从其他`ng-repeat`元素获取`data`到当前元素指令

检测指令中的 ng-repeat 元素长度变化

量角器:by.model 在自定义指令中找不到元素