如何在处理子节点后调用Angular指令中的函数?

Dan*_*edo 11 angularjs angularjs-directive

我正在尝试使用Angular JS指令来居中div的内容.

这是模板的简化版本:

<div id="mosaic" class="span12 clearfix" s-center-content>
    <div ng-repeat="item in hits" id="{{item._id}}" >
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

这是指令:

 module.directive('sCenterContent', function() {
    var refresh = function(element){
        var aWidth= element.innerWidth();
        var cWidth= element.children()[0].offsetWidth;
        var cHeight= element.children()[0].offsetHeight;
        var perRow= Math.floor(aWidth/cWidth);
        var margin=(aWidth-perRow*cWidth)/2;
        if(perRow==0){
            perRow=1;
        }
        var top=0;
        element.children().each(function(index, child){
            $(child).css('margin-left','0px');
            if((index % perRow)==0){
                $(child).css('margin-left',margin+'px');
            }
        });
    };
    return {
        link : function(scope, element, attrs) {
            $(window).resize(function(event){
                refresh(element);
            });
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

它基本上浮动一些内部div并为每行中的第一个div添加一个边距,因此内容居中.

调整浏览器大小时,这可以正常工作.当我尝试在初始化后进行刷新时出现问题.

我已尝试使用此问题中所见的帖子链接功能.预链接和后链接函数按预期顺序调用,但不会在具有s-center-content指令的elemenet的子节点被渲染之后调用.由于没有找到孩子,因此刷新调用失败.

如何打电话刷新以确保孩子们已被处理?

thr*_*eez 7

我认为使用angular的$ watch是一个更好,更优雅的解决方案:

link : function(scope, element, attrs) {
            $(window).resize(function(event){
                refresh(element);
            });

            var watchCount = 0,
            unWatcher = $watch(
                function() {
                   return $('*[s-center-content] img').length !== 0;
                },
                function() {
                   // ensure refresh isn't called the first time (before the count of elements is > 0)
                   if (++watchCount === 1) {
                       return;
                   }

                   refresh(element);                   

                   // stop watching the element now that refresh has been called
                   unWatcher();
                }, true);
        }
Run Code Online (Sandbox Code Playgroud)

关于停止观看:AngularJS:清除$ watch


Roy*_*ove 5

这是一个反复出现的问题(某处有一个与此相关的问题,以及谷歌论坛中的一个帖子......)

Angular无法知道dom何时完成,它只能知道它调用的函数何时返回(并且任何promise都被解析).如果这些函数是异步的并且没有回调或承诺,则无法通知.

我已经看到它完成的方式(以及我完成它的方式)是使用setInterval定期检查DOM以查看它是否处于已完成状态.我讨厌这个解决方案,并会感激一个替代方案,但它确实完成了工作.


Dan*_*edo 1

终于成功了!

我使用 livequery 插件并将以下行添加到链接方法的末尾:

$('*[s-center-content] > *').livequery( function(event){
    refresh(element);
});
Run Code Online (Sandbox Code Playgroud)

我使用指令选择元素的任何第一级子元素(当前和未来),s-center-content并附加一个处理程序,该处理程序在元素添加到 DOM 时调用。

编辑

最后一点。我的内容布局主要取决于具有动态评估src属性的内部图像。因此,为了使其工作,我必须将代码更改为:

$('*[s-center-content] img').livequery( function(event){
    $(this).load(function(){
       refresh(element);                    
    });
});
Run Code Online (Sandbox Code Playgroud)

将左浮动 div 居中的指令的完整代码如下。请注意,它依赖于向行中的第一个 div 添加计算出的边距。

module.directive('sCenterContent', function() {
    var refresh = function(element){
        var aWidth= element.innerWidth();
        var cWidth= element.children()[0].offsetWidth;
        var cHeight= element.children()[0].offsetHeight;
        var perRow= Math.floor(aWidth/cWidth);
        var margin=(aWidth-perRow*cWidth)/2;
        if(perRow==0){
            perRow=1;
        }
        var top=0;
        element.children().each(function(index, child){
            $(child).css('margin-left','0px');
            if((index % perRow)==0){
                $(child).css('margin-left',margin+'px');
            }
        });
    };
    return {
        link : function(scope, element, attrs) {
            $(window).resize(function(event){
                refresh(element);
            });
            $('*[s-center-content] img').livequery( function(event){
                $(this).load(function(){
                    refresh(element);                   
                });
            });
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

  • 如果你查看插件[代码](https://github.com/brandonaaron/livequery/blob/master/jquery.livequery.js),你会注意到它还使用了`setTimeout(fn, 20)`来匹配新元素。所以它在友好视图“pack”中是一个肮脏的解决方案。 (4认同)