2014-02-13 16 views
7

In Angular lernen Ich erstelle eine einfache Galerie, die gezoomt werden kann. Meine anfängliche Implementierung verwendete eine einfache ng-Wiederholung, aber ich entdeckte schnell, dass ich basierend auf dem Zoom der Galerie Dinge wie die URL-Quelle (von kleinen zu mittleren Thumbs) und wahrscheinlich die CSS auf Bildunterschriften etc. ändern wollte.Angular Direktiven beobachten externe Modelle

<div class="photoHolder" ng-repeat="photo in photos | filter:{caption:query} | orderBy:orderProp" ng-attr-style="transition: .3s ease; width: {{thumbWidth}}px; height: {{thumbWidth}}px;"> 
    <div class="photoClass" data-id="{{photo.id}}" ng-attr-style="background-image:url({{zoomSize < 5 ? photo.thumb_url : photo.medium_url}})"></div> 
    <div class="caption">{{photo.caption}}</div> 
    <div class="caption">{{photo.date}}</div> 
</div> 

Also wechselte ich zu einer viel sauberen Richtlinie:

<gal-photo class="photoHolder" ng-repeat="photo in photos | filter:{caption:query} | orderBy:orderProp"/> 

aber die einzige Art, wie ich die Richtlinie Element der Zoomänderung zu reagieren bekommen könnte, ist eine Uhr auf den Zoom innerhalb des Link hinzufügen zu das Element:

link: function(scope, element, attrs) { 
    var image = new Image(); 
    scope.photo.url = scope.zoomSize < 5 ? scope.photo.thumb_url : scope.photo.medium_url; 
    scope.$watch('thumbWidth', function() { 
      scope.photo.url = scope.zoomSize < 5 ? scope.photo.thumb_url : scope.photo.medium_url; 
     element.attr('style', 'transition: .3s; width: ' + scope.thumbWidth + 'px; height: ' + scope.thumbWidth + 'px;'); 
    }); 
} 

Ich weiß, dass Sie Uhren nicht missbrauchen sollen, und meine Angst ist, dass Sie mit 500 Elementen in der Galerie 500 Uhren machen. Aber ich kann keine Anleitung finden, auf externe Eingaben innerhalb wiederholender Anweisungen zu reagieren. Die beiden Galerien scheinen ungefähr gleich zu sein, aber ich frage mich, ob ich das falsch mache? Hier ist eine Geige für die original gallery und eine Geige für die directive version.

+0

Ich mochte Ihre ursprüngliche Lösung mit ng-attr-Stil, weil es weniger Code ist, aber es klingt, als ob dies mehr eine Frage der Leistung ist. Ich würde Fragen wie diese prüfen-> http://stackoverflow.com/questions/20702140/improving-nested-ng-repeat-directive-performance – koolunix

+0

Ja, ich habe das bereits überprüft ... Ich suche nach Anleitung in die Art, wie Menschen mit externen Eingaben in Modellen umgehen. Wie gesagt, die Performance ist nicht merklich anders. Ich bevorzuge die Direktive, da es weniger HTML ist und mächtiger scheint, ich habe mich nur gefragt, ob ich es falsch mache. –

+0

Das ist auch ein wirklich gutes: http://StackOverflow.com/Questions/9682092/Databinding-in-angularjs/9693933#9693933 – koolunix

Antwort

3

Ich denke, Beyers ist richtig, dass Uhren tatsächlich ziemlich effizient sind.

Dennoch ist hier, wie Sie dies unter Verwendung einer übergeordneten Richtlinie für das gesamte Bild Galerie mit einem einzigen Uhr tun konnte:

myApp.directive('imageGallery', function() { 
return { 
    restrict: 'A', 
    controller: function($scope, $element, $attrs) { 
     function updatePhotos() { 
      $element.children().attr('style', 'transition: .3s; width: ' + $scope.thumbWidth + 'px; height: ' + $scope.thumbWidth + 'px;'); 
      $scope.photos.forEach(function(photo){ 
       photo.url = $scope.zoomSize < 5 ? photo.thumb_url : photo.medium_url; 
      }); 
     }; 

     this.updatePhotos = updatePhotos; 
    }, 
    link: function(scope, element, attrs, ctrl) { 
     scope.$watch('thumbWidth', function() { 
      ctrl.updatePhotos(); 
     }); 
     ctrl.updatePhotos(); 
    } 
} 
}); 

(full fiddle here)

Beachten Sie, dass ich die zentrale Aktualisierung gesetzt haben Logik in die controller anstatt die link Funktion. Das ist hier nicht unbedingt notwendig, aber es könnte in der Zukunft nützlich sein, weil das Controller-Objekt für die untergeordneten galPhoto-Direktiven sichtbar wäre. (Siehe die beiden "NOTE" Kommentare in der Geige.)

+0

Heilige Kuh, die im Vergleich zu den anderen Versionen glatt ist. (Beyers und mein Original). –

+1

Heh, danke. Es ist jedoch erwähnenswert, dass, da jede Instanz der galPhoto-Direktive ihr "Foto" -Objekt über die {{}} - Interpolation referenziert, die Anzahl der Uhren in dieser Lösung immer noch proportional zur Anzahl der Fotos ist ... sie sind nur unter der Haube statt in deinem Code. – anandthakker

6

Ihr Anwendungsfall ist ein guter Kandidat für $ scope events. Haben Sie eine Uhr in Ihrem Controller:

$scope.$watch('thumbWidth', function() { 
    $scope.$broadcast('thumbWidthChange'); 
}); 

Und dann in der Richtlinie Register Zuhörer für diese Veranstaltung:

scope.$on('thumbWidthChange', function(){ 
    scope.photo.url = scope.zoomSize < 5 ? scope.photo.thumb_url : scope.photo.medium_url; 
    element.attr('style', 'transition: .3s; width: ' + scope.thumbWidth + 'px; height: ' + scope.thumbWidth + 'px;'); 
}); 

Scope Ereignis-Listener nur aufgerufen werden, wenn ihre Ereignisse ausgelöst werden, so sollte dies die Uhr begrenzen Liste und optimieren Sie die Leistung.

Hier ein updated fiddle ist basierend auf dem Beispiel der Ereignisse Methode: http://jsfiddle.net/dv7fy/1/

Als Randbemerkung, die Leistung von Angular Uhren skaliert besser als das, was die meisten denken, einen Blick auf dieses Beispiel haben (immer noch auf Angular 1,0. 3, sollte in der neuesten Version noch besser sein): http://jsfiddle.net/mhevery/cXMPJ/11/

Verwandte Themen