Как вызвать функцию в директиве Angular после обработки дочерних узлов?

Я пытаюсь использовать директиву Angular JS для центрирования содержимого div.

Это упрощенная версия шаблона:

<div id="mosaic" class="span12 clearfix" s-center-content>
    <div ng-repeat="item in hits" id="{{item._id}}" >
    </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);
            });
        }
    };
});

В основном он плавает некоторые внутренние div и добавляет маркер к первому div в каждой строке, поэтому содержимое центрируется.

Это отлично работает при изменении размера браузера. Проблема возникает, когда я пытаюсь выполнить обновление сразу после инициализации.

Я пробовал с функцией связывания сообщений, как показано в этом вопросе. Функции предварительной ссылки и пост-ссылки вызывают в ожидаемом порядке, но не после того, как будут отображены дочерние элементы элемента с директивой s-center-content. Вызов обновления завершается неудачей, так как ни один из них не найден.

Как мне сделать звонок для обновления, обеспечив обработку детей?

Ответ 1

Наконец-то сделал это!

Я использовал плагин livequery и добавил следующую строку в конец метода ссылки:

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

Я выбираю любого дочернего элемента первого уровня (текущий и будущий) элемента с директивой s-center-content и присоединяю обработчик, который вызывается, когда элементы добавляются в DOM.

ИЗМЕНИТЬ

Последняя заметка. Макет моего контента зависит главным образом от внутренних изображений с динамически оцениваемыми атрибутами src. Чтобы заставить его работать, мне пришлось изменить код на это:

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

Полный код директивы, в которой лежат левые плавающие divs с центром, выглядит следующим образом. Обратите внимание, что он полагается на добавление вычисленного поля в первый 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);                   
                });
            });
        }
    };
});

Ответ 2

Я думаю, что использование 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);
        }

О прекращении просмотра: AngularJS: очистить $watch

Ответ 3

Это повторяющаяся проблема (где-то там проблема, связанная с этим, а также поток на форумах google..)

Angular не имеет возможности узнать, когда dom закончен, он может знать только, когда разрешены функции, которые он вызывает return (и любой promises). Если эти функции асинхронны и не имеют обратного вызова или обещания, нет способа получить уведомление.

То, как я это видел (и то, как я это сделал), - это setInterval, который периодически проверяет DOM, чтобы увидеть, завершено ли оно в завершенном состоянии. Я ненавижу это решение и буду благодарен за альтернативу, но он выполняет эту работу.

Ответ 4

Я считаю, что это можно сделать с помощью css. Являются ли элементы, центрированные по цели, независимо от числа, подобного этому?

[]  []  []  []  []

    []  []  []

Если это так, это возможно с помощью css и может быть достигнуто с гораздо меньшей сложностью. Вот пример:

http://codepen.io/thetallweeks/pen/kvAJb