2013-04-10 3 views
11

Ich versuche eine Angular JS-Direktive zu verwenden, um den Inhalt eines div zu zentrieren.Wie kann eine Funktion in einer Angular-Direktive aufgerufen werden, nachdem die Kindknoten verarbeitet wurden?

Dies ist die vereinfachte Version der Vorlage ist:

<div id="mosaic" class="span12 clearfix" s-center-content> 
    <div ng-repeat="item in hits" id="{{item._id}}" > 
    </div> 
</div> 

Dies ist die Richtlinie:

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); 
      }); 
     } 
    }; 
}); 

Es schwimmt im Grunde einige innere divs und fügt eine Marge auf den ersten div in jeder Reihe, also ist der Inhalt zentriert.

Dies funktioniert gut, wenn der Browser die Größe ändert. Das Problem tritt auf, wenn ich versuche, nach der Initialisierung eine Aktualisierung durchzuführen.

Ich habe mit der Post-Linking-Funktion wie in this question gesehen versucht. Die Pre-Link- und Post-Link-Funktionen werden in der erwarteten Reihenfolge aufgerufen, aber nicht nachdem die Children des Elemenet mit der s-center-content-Direktive gerendert wurden. Der Aufruf zum Aktualisieren schlägt fehl, da keine Kinder gefunden werden.

Wie kann ich einen Anruf tätigen, um sicherzustellen, dass die Kinder verarbeitet wurden?

Antwort

1

Endlich geschafft!

verwendete ich Livequery-Plugin und hinzugefügt, um die folgende Zeile am Ende des Verbindungsmethode:

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

ich wählen Sie eine beliebige erste Ebene Kind (aktuelle und zukünftige) des Elements mit der s-center-content Richtlinie und einen Handler anhängen das wird aufgerufen, wenn die Elemente dem DOM hinzugefügt werden.

EDIT

Eine letzte Bemerkung. Das Layout meiner Inhalte hängt hauptsächlich von inneren Bildern mit dynamisch bewerteten src Attributen ab. So, damit es funktioniert hatte ich den Code, dies zu ändern:

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

Der vollständige Code der Richtlinie, die linken Floating divs legt zentriert ist wie folgt. Beachten Sie, dass das Hinzufügen eines berechneten Randes zum ersten div in der Zeile erforderlich ist.

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);     
       }); 
      }); 
     } 
    }; 
}); 
+1

Gut gemacht, das ist sehr praktisch! Ich werde versuchen, den Google-Gruppen-Thread und das Problem in eckig zu finden, das über dieses Problem spricht, und ich werde auf Ihre Antwort verweisen. –

+0

Danke für die Mühe Roy. –

+4

Wenn Sie sich die Plugins [code] (https://github.com/brandonaaron/livequery/blob/master/jquery.livequery.js) ansehen, werden Sie feststellen, dass sie auch 'setTimeout (fn, 20)' to verwendet hat Passe neue Elemente an. Es ist also eine schmutzige Lösung in freundlicher 'Pack'. – FelikZ

5

Dies ist ein wiederkehrendes Thema (Irgendwo ein Problem damit verbundenen da ist, sowie ein roter Faden in den Google-Foren ..)

Angular keine Möglichkeit, wenn der Dom fertig zu wissen haben, kann es nur wissen, wenn die Funktionen, die es aufruft, zurückkehren (und alle Versprechen werden aufgelöst). Wenn diese Funktionen asynchron sind und keinen Rückruf oder eine Zusage haben, gibt es keine Möglichkeit, benachrichtigt zu werden.

Die Art, wie ich es gesehen habe (und die Art, wie ich es gemacht habe), ist mit einem setInterval, das das DOM regelmäßig überprüft, um zu sehen, ob es in einem abgeschlossenen Zustand ist. Ich hasse diese Lösung und werde für eine Alternative dankbar sein, aber es macht die Arbeit erledigt.

+0

Was ist das übergeordnete Element zu beobachten? Würde ich mit Kinderzusätzen benachrichtigt werden? Wenn ja, könnte das der richtige Weg sein. Ich werde es prüfen! –

7

denke ich $watch Winkel der Verwendung ist eine bessere, elegantere Lösung:

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); 
     } 

über mehr beobachten: AngularJS : Clear $watch

+1

Dies ist sehr clever - vielleicht ein bisschen mehr Beschreibung auf die Antwort wird es sichtbarer machen. –

+0

Das ist ziemlich cool. Möchte nur auf $ (Selektor) .length sehen. Obwohl nicht ganz sicher, ob das immer funktioniert. – David

0

Ich glaube, dies mit CSS erreicht werden kann. Ist das Ziel zentriert Elemente unabhängig von der Anzahl wie folgt?

[] [] [] [] [] 

    [] [] [] 

Wenn ja, ist dies definitiv mit CSS möglich und könnte mit viel weniger Komplexität erreicht werden. Hier ist ein Beispiel:

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

Verwandte Themen