2013-02-20 17 views
7

Ich bin in einem Problem, wo ich an die Ausgabe einer Funktion innerhalb einer ng-Repeat-Schleife binden möchten. Ich stelle fest, dass die Funktion zweimal pro Element statt einmal aufgerufen wird, wie ich es erwarten würde. Hier ist der ng-repeat Abschnitt (man beachte die calcRowTotal() -Aufruf am Ende):Funktion aufgerufen mehrmals in AngularJS Abschnitt

<tr ng-repeat="row in timesheetRows"> 
    <td> 
     <select ng-model="row.categoryID"> 
      <option ng-repeat="category in categories" value="{{category.id}}"> 
       {{category.title}} 
      </option> 
     </select> 
    </td> 
    <td ng-repeat="day in row.dayValues"> 
     <input type="text" ng-model="day.hours" /> 
    </td> 
    <td>{{calcRowTotal($index, row)}}</td> 
</tr> 

Die calcRowTotal() Funktion wird unten gezeigt:

$scope.calcRowTotal = function (index, row) { 
    console.log('calcRowTotal - Index: ' + index); 
    var total = 0; 
    for (var i = 0; i < row.dayValues.length; i++) { 
     var num = parseFloat(row.dayValues[i].hours); 
     if (isNaN(num)) { 
      num = 0; 
      //this.dayValues[i].hours = 0; 
     } 
     total += num; 
    } 
    //updateDayTotals(); 
    return total; 
} 

Ein Beispiel für eines der Elemente sein iterierten durch Als nächstes wird gezeigt:

{ 
    categoryID: 2, 
    dayValues: [ 
        { day: $scope.days[0], hours: 5 }, 
        { day: $scope.days[1], hours: 0 }, 
        { day: $scope.days[2], hours: 3 }, 
        { day: $scope.days[3], hours: 0 }, 
        { day: $scope.days[4], hours: 2 }, 
        { day: $scope.days[5], hours: 5 }, 
        { day: $scope.days[6], hours: 8 } 
    ] 
} 

ich folgendes in der Konsole (zwei Elemente befinden sich in der Sammlung ich Schleifen) zu sehen:

Ich könnte sicherlich eine "rowTotal" -Eigenschaft machen, würde aber lieber an "Live" -Daten binden, die von der oben gezeigten Funktion bereitgestellt werden. Hoffentlich ist die Vervielfältigung etwas, das ich einfach vermisse, daher schätze ich jede Rückmeldung darüber, warum ich die Vervielfältigung sehe. Als Nebenbemerkung, da die Daten in einem der Textfelder sich ändern, muss ich auch die Zeilensummen aktualisieren, so dass ich vielleicht einen anderen Ansatz brauche. Interessiert, diese spezielle Situation zuerst zu verstehen .... aber definitiv nicht die Verdoppelung, weil es möglicherweise viele Reihen möglicherweise geben könnte.

Hier ist ein Beispiel: http://jsfiddle.net/dwahlin/Y7XbY/2/

+0

Dies ist ein Duplikat von http://stackoverflow.com/q/14973792/259038, obwohl es nicht sofort offensichtlich gewesen sein könnte. –

+0

Danke Josh. Habe ziemlich viel Zeit mit der Suche verbracht, aber ich habe das nicht gesehen. Schätze die Informationen. –

+0

Ja, das ist definitiv kein "delete this" Art von Duplikat, da es nicht offensichtlich ist, dass es sich um denselben Fall handelt. Ich wollte nur den Kreis für zukünftige Zuschauer schließen. –

Antwort

13

Es ist, weil Sie auf eine Funktion Ausdruck sind verbindlich hier:

<td>{{calcRowTotal($index, row)}}</td> 

Was, dass sie diese Funktion nicht zwingen, an jedem Punkt neu bewertet werden, auf jedem verdauen. Um dies zu verhindern, sollten Sie diesen Wert vorberechnen und ihn zunächst in Ihr Array einfügen.

Eine Möglichkeit, das zu tun, ist eine Uhr auf Ihrem Array einzurichten:

$scope.$watch('timesheetRows', function(rows) { 
    for(var i = 0; i < value.length; i++) { 
    var row = rows[i]; 
    row.rowTotal = $scope.calcRowTotal(row, i); 
    } 
}, true); 

Dann alles, was Sie tun müssen, binden sich an diesen neuen Wert ist:

<td>{{row.rowTotal}}</td> 
+0

Danke Blesh - wusste nicht, dass es das tun würde, aber es macht Sinn. –

+0

Es ist ehrlich gesagt wahrscheinlich keine "große Sache". Da es sich um eine clientseitige App handelt und es nur einen Benutzer gibt, können Sie, wenn es keine Leistungsprobleme verursacht, diese belassen, wenn es für Sie einfacher ist, sie zu pflegen. Unabhängig davon habe ich einen Pseudo-Code für eine vorgeschlagene Lösung in meiner Antwort. –

+0

+1 Aber warum hast du 'angular.forEach' hier nicht benutzt? Scheint so, als hätte es den Code ein wenig runtergeschnitten. Außerdem sollten Sie erwähnen, dass Ausdrücke bei jedem Digest mindestens einmal * genannt werden und wir nicht garantieren können, wie oft. –

0

Ich hatte eigentlich ein ähnliches Problem in letzter Zeit.

Endete durchlaufen durch jedes Unterobjekt und bindet die Summen an ein Modell. Sollte kein Problem sein, besonders wenn Sie nur die Summe für Anzeigezwecke verwenden.

z.

und durchlaufen Sie jede Zeile.

+4

Viele AngularJS-Projekte verwenden jQuery nicht, aber sie können das funktional ähnliche 'angular.forEach' verwenden. –

1

Es ist total, weil Sie an einen Funktionsausdruck binden, wie @Ben Lesh vorgeschlagen hat. Irgendwie brachte mich die Verwendung von $ watch dazu, dieselbe Funktion zweimal auszuführen. Die Lösung für die doppelte Ausführung, die wir verwendeten, ist die Verwendung von ng-init für den Funktionsaufruf. einfach eine Variable init mit Funktion als Return-Wert zu schaffen, und dass, wie unten in ur Ausdruck verwenden:

<tr ng-repeat="row in timesheetRows" ng-init="rowTotalValue=calcRowTotal($index, row)"> 
<td> 
    <select ng-model="row.categoryID"> 
     <option ng-repeat="category in categories" value="{{category.id}}"> 
      {{category.title}} 
     </option> 
    </select> 
</td> 
<td ng-repeat="day in row.dayValues"> 
    <input type="text" ng-model="day.hours" /> 
</td> 
<td>{{rowTotalValue}}</td> 

Das ist für mich gearbeitet, wo ich ein einziges Attribut der Reihe vorbei. Nicht mit $ index versucht. Aber ich gehe davon aus, dass es funktionieren sollte.

Verwandte Themen