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

时间:2013-07-26 13:39:10

标签: javascript html angularjs angularjs-directive

我正在尝试构建一个自定义指令,将其内容重新排列为网格。 我想要转换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();

            // ...
    }; 
}]);

我错过了什么?

2 个答案:

答案 0 :(得分:0)

要实现重新排序,您有以下几种选择:

  1. 操纵DOM。恕我直言,这是最不受欢迎的方式,它的角度不是很大。
  2. 重新排序链接函数中ngRepeat中使用的数组([1,2,3])。
  3. 使用orderBy过滤器(doc
  4. 我已经创建了一个演示2和3的插件,希望它可以提供帮助。 http://plnkr.co/edit/vrgeBoJZiG6WMu4Rk46u?p=preview

答案 1 :(得分:0)

有几种方法可以解决这个问题。您将看到的最简单和最常见的解决方案是评论建议 - 利用$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指令将完成。&#34}; 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 - 展示两种方法的简单演示