2013-02-20 9 views
7

Występuje problem, który chcę powiązać z wyjściem funkcji wewnątrz pętli ng-repeat. Zauważyłem, że funkcja jest wywoływana dwa razy na przedmiot, a nie raz, jak się spodziewałam. Oto odcinek ng-repeat (zawiadomienie calcRowTotal() wezwanie na końcu):Funkcja wywołana wiele razy w AngularJS Powtórz Sekcja

<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> 

Funkcja calcRowTotal() jest wyświetlana obok:

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

Przykładem jednego z przedmiotów będących powtórzyć poprzez pokazano obok:

{ 
    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 } 
    ] 
} 

widzę następujące w konsoli (dwa przedmioty są obecnie w kolekcji mam przelotowego):

calcRowTotal - Index: 0 
calcRowTotal - Index: 1 
calcRowTotal - Index: 0 
calcRowTotal - Index: 1 

Mogę na pewno utworzyć właściwość "rowTotal", ale wolałbym powiązać dane "na żywo" z funkcją pokazaną powyżej. Mam nadzieję, że duplikacja jest czymś prostym, czego mi brakuje, dlatego doceniam wszelkie uwagi na temat tego, dlaczego widzę duplikację. Na marginesie, ponieważ dane w jednym ze zmian w polu tekstowym muszę aktualizować również sumy wierszy, może potrzebuję innego podejścia. Interesuje się przede wszystkim zrozumieniem tej konkretnej sytuacji ... na pewno nie chce duplikacji, ponieważ potencjalnie może być wiele wierszy.

Oto przykład: http://jsfiddle.net/dwahlin/Y7XbY/2/

+0

To jest duplikat http://stackoverflow.com/q/14973792/259038, chociaż może nie było to od razu oczywiste. –

+0

Dzięki Josh. Spędziłem sporo czasu na wyszukiwaniu, ale tego nie widziałem. Doceń informacje. –

+0

Tak, to zdecydowanie nie jest "duplikat" tego duplikatu, ponieważ nie jest oczywiste, że są one tym samym przypadkiem. Chciałem tylko zamknąć pętlę dla przyszłych widzów. –

Odpowiedz

13

To dlatego jesteś wiążące do wyrażenia funkcyjnego tutaj:

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

Co, że to siła, która funkcję zostać ponownie na każdej pozycji, na każdym Digest. To, co chcesz zrobić, aby temu zapobiec, wstępnie obliczyć tę wartość i umieścić ją w swojej macierzy na początku.

Jednym ze sposobów, aby to zrobić jest stworzenie zegarka na swojej tablicy:

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

Następnie wszystko co musisz zrobić, to wiążą się z tej nowej wartości:

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

Dzięki Blesh - nie zdawałem sobie sprawy, że to zrobi, ale ma to sens. –

+0

To chyba nie jest "wielka sprawa". Ponieważ jest to aplikacja po stronie klienta i istnieje tylko jeden użytkownik, jeśli nie powoduje problemów z wydajnością, możesz go opuścić, jeśli jest łatwiejszy w utrzymaniu. Niezależnie od tego, mam pewien kod psuedo dla proponowanej poprawki w mojej odpowiedzi. –

+0

+1 Ale dlaczego nie użyłeś tutaj słowa "kątowy. Wygląda na to, że mogło trochę skrócić kod. Powinieneś też wspomnieć, że wyrażenia będą wywoływane * przynajmniej raz * w trakcie każdego skrótu i ​​nie możemy zagwarantować, ile razy. –

0

I rzeczywiście miał podobny problem ostatnio.

Skończyło się na iteracji przez każdy pod-obiekt i powiązaniu sumy z modelem. Nie powinno to stanowić problemu, zwłaszcza jeśli używasz całości tylko do celów wyświetlania.

np.

// Reset to Zero 
$scope.rowTotal = 0; 

jquery.each($scope.row, function(key, value) { 
$scope.totalRow += value.hours; 
}); 

i iteracja w każdym rzędzie.

+4

Wiele projektów AngularJS nie korzysta z jQuery, ale mogą one używać funkcjonalnie podobnego "kątowego.do każdego". –

1

Jest całkowicie związany z wyrażeniem funkcji, jak sugeruje @Ben Lesh. W jakiś sposób za pomocą funkcji $ watch otrzymałem także dwukrotne wykonanie tej samej funkcji. Rozwiązaniem jest powstrzymanie się od podwójnej realizacji, której używaliśmy, za pomocą polecenia ng-init dla wywołania funkcji. Wystarczy utworzyć zmienną startowy z powrotu funkcji jako wartość i używać w ur ekspresji, jak poniżej:

<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> 

ten pracował dla mnie, gdzie ja mijał jeden atrybut rzędu. Nie próbowano jednak z $ index. Ale zakładam, że to powinno działać.

Powiązane problemy