2013-03-22 20 views
30

Ich habe manchmal Schwierigkeiten, AngularJS zu verstehen. So habe ich eine grundlegende Array in meinem Controller wieAngularJS wird nicht aktualisiert ngRepeat beim Aktualisieren des Arrays

$scope.items = ["a","b","c"] 

Ich bin ngRepeating in meiner Vorlage über die Element-Array ng-repeat = "Artikel in Artikel". Super gerade so weit. Nach ein paar UX-Aktionen möchte ich ein paar neue Sachen in mein Array pushen.

$scope.items.push("something"); 

So, in 50% der Zeit wird das neue Element der Ansicht hinzugefügt. Aber die anderen 50% passiert nichts. Und es ist super frustrierend; bc, wenn ich das innerhalb von $ scope umgehe. $ apply(), ich habe einen "$ digest in progress" -Fehler bekommen. Das Einpacken in $ timeout hilft auch nicht.

Und wenn ich meinen Elementbereich mit der Chrome-Erweiterung überprüfe; Ich kann sehen, dass die neuen Daten vorhanden sind und der Wert $ scope.items korrekt ist. Aber die Ansicht kümmert sich nicht darum, das dem DOM hinzuzufügen.

Danke!

+0

können Sie unter http://jsfiddle.net/ –

+2

eine Demo erstellen, die sicherlich mit dem Digest-Zyklus zusammenhängt. Sie müssen den Code eingeben, den Sie zum Aktualisieren des Arrays verwenden. –

+2

Ich bekomme dieses Problem auch, würde eine Antwort lieben! – Samuel

Antwort

21

Sie ändern den Bereich außerhalb des Winkels $digest Zyklus 50% der Zeit.

Wenn es einen Rückruf gibt, der nicht von angularjs ist; (posibbly jquery). Sie müssen $apply aufrufen, um einen $digest Zyklus zu erzwingen. Aber Sie können nicht $apply während in $digest Zyklus aufrufen, weil jede Änderung, die Sie vorgenommen haben, automatisch bereits reflektiert wird.

Sie müssen wissen, wenn der Rückruf nicht aus Winkel ist und sollte dann nur $apply aufrufen.

Wenn Sie nicht wissen, und nicht in der Lage zu lernen, hier ist ein netter Trick:

var applyFn = function() { 
    $scope.someProp = "123"; 
}; 
if ($scope.$$phase) { // most of the time it is "$digest" 
    applyFn(); 
} else { 
    $scope.$apply(applyFn); 
} 
+0

Ich glaube, Sie sollten '$ scope. $$ phase' vermeiden. Es ist eine interne Variable, und Sie sollten sich nicht darauf verlassen, wenn Sie dies tun. Die beste Lösung wäre, '$ apply' zu verwenden, wo Sie absolut sicher sind, dass kein' $ apply' bereits in Bearbeitung ist. Und deshalb frage ich nach den Codes, die den Umfang aktualisieren könnten. –

+0

Es ist kein guter Code, ich stimme dem zu. Aber es funktioniert und '$$ Phase' ist sehr konsistent und zuverlässig; zumindest wird es Ihren Code nicht unerwartet brechen, außer dass er zwischen den Releases geändert werden kann. –

+0

Es ist. Ich habe es schon benutzt. Die Frage ist, ob wir nicht wissen, ob dies in der nächsten Minor-Version für seinen internen Status-Controller bricht. Ich denke nur darüber nach, dass es wahrscheinlich einen besseren Ort gibt, um das '$ apply' sicher anzubringen. –

0

ich hatte das gleiche Problem, und meine Verlegenheit war zu beobachten, welche Controller in verschachtelten Richtlinien genannt werden.

# Parent Controller 
app.controller 'storeController', ($scope, products) -> 

    $scope.cart = ["chicken", "pizza"] 
    $scope.addToCart = (item) -> 
    $scope.cart.push item 

    # from service 
    products.get().then (items) -> 
    $scope.products = items 

# Parent Directives 
app.directive 'storeContainer', ($scope, config) -> 
    restrict: 'E' 
    templatUrl: 'store-container.html' 
    controller: 'storeController' 

# Nested Directive 
app.directive 'storeFront', ($scope, config) -> 
    restrict: 'E' 
    templatUrl: 'store-front.html' 
    controller: 'storeController' 

# Parent Template templates/directives/store-container.html 
<div ng-repeat="item in cart">{{ item }}</div> 
<strore-front></store-front> 

# Nested Template templates/directives/store-front.html 
<ul ng-repeat="item in products"> 
    <li ng-click"addToCart(item)">{{ item }}</li> 
</ul> 

Der Fehler ist hier die verschachtelte Richtlinie in Prototypkette (ein Duplikat storeController) einen zweiten Controller erzeugt, das die übergeordnete Vorlage keinen Zugang zu. So lösen Sie das verschachtelte Controller schreiben wie folgt:

# Nested Directive 
app.directive 'storeFront', ($scope, config) -> 
    restrict: 'E' 
    templatUrl: 'store-front.html' 

Es gibt bessere Möglichkeiten, um die Vererbungskette zu schaffen, aber das wird das Problem für viele Menschen das Lernen AngularJS lösen.

4

Wie von Umur Kontacı hervorgehoben, machen Sie manchmal Modelländerungen außerhalb des Digest-Zyklus. Anstatt dieses Problem zu umgehen und herauszufinden, ob Sie sich in einem Kontext "apply/digest" befinden, sollten Sie jedoch sicherstellen, dass dies nicht geschieht.

Der Hauptgrund für dieses Problem ist, dass Ihre Funktion als Reaktion auf ein DOM-Ereignis aufgerufen wird. Z.B.

Dies ist, wo Ihre $ apply() gehen muss, nicht innerhalb der Funktion. Sonst wird der ganze Code früher oder später mit solchen Unterscheidungen übersät sein.Angenommen, es ist ein Bereich im Rahmen dieser Event-Handler, können Sie schreiben:

jQuery('.some-element').click(function() { 
    $scope.$apply(function() { seeminglyProblematicCode() }) 
}) 

Es gibt jedoch eine Einschränkung ist, dass Sie sich bewusst sein müssen: Wenn Sie ein Klick-Ereignis aus dem Code auslösen, werden Sie laufen in das Problem, dass ein Digest-Zyklus bereits in Arbeit ist. Hier benötigen Sie das $ Timeout. Die Antworten auf this question decken dieses Problem sehr gut ab.

Verwandte Themen