2016-02-25 10 views
8

Mam aplikację AngularJS 1.4 * działającą lokalnie (jeszcze). Ta aplikacja jest obsługiwana przez interfejs API RESTFul Laravel 5.1.Dlaczego mój watcher zostaje wywołany dwukrotnie na tej samej zmianie?

Muszę zrobić tę aplikację, która reprezentuje wycieczkę. Pakiet składa się z dni, od 0 do N dni. Każdego dnia mamy listę usług, od 0 do N usług. I hotel.

Mój serwer internetowy, z którego korzysta moja aplikacja laravel, dostarcza mi wstępnie ustawiony pakiet zawierający listę dni: każdy z listą usług i danymi hotelowymi (dotychczas niewykorzystane). W odpowiedzi mam listę właściwości pakietu (które nie ma teraz znaczenia) i tablicę dni, o nazwie days_info. Ta odpowiedź jest umieszczana w $scope.package na moim PackageController. PackageController również deklaruje dyrektywę o nazwie packageBlock, która składa się z listy dni i kilku innych danych dla pakietu.

<div ng-repeat="day in package.days_info" class='row'> 
    <div class='col-md-12'> 
     <package-days-block></package-days-block> 
    </div> 
</div> 

Wewnątrz dyrektywy <package-days-block> mam kolejną pozycję, aby przejrzeć listę usług wewnątrz każdego dnia.

<div class='container-fluid' ng-repeat='service in day.services' ng-controller="ServiceController"> 
    <service-block></service-block> 
</div> 

To miejsce, gdzie zaczyna się problem: do mojego undestandment, mam teraz $scope.service wewnątrz mojego ServiceController. Tak, zacząłem to zmienić na moje potrzeby wewnątrz ServiceController poprzez $scope.service.

Obiekt $ scope.service ma atrybut o nazwie service_id. Umieszczam na nim odbiornik/obserwatora, więc w każdej chwili zmieniany jest $ scope.service.service_id, pytam o kolejny service_table (przechowuje informacje o usługach, jest to oparte na wcześniejszym wybranym identyfikatorze usługi lub zmienionym przez użytkownika) i umieść go w $scope.service.table.

// ServiceController 
$scope.reloadServicesTable = function(service_id, service_day, date, paxes){ 
    MandatoryService.getServiceTable(service_id, service_day, date, paxes) 
    .then(
     function(service_data) { 
      $scope.service.table = service_data; 
     }, 
     ... 
    ); 

reloadServicesTable nazywa na strażnika za service_id zmian.

// ServiceController 
$scope.$watch(
    'service.service_id', // Places the watcher to watch the changes on the service's ID. 
    function(new_service, old_service) { 
     if(new_service === old_service) 
      return; 

     $scope.reloadServicesTable($scope.service.service_id, $scope.service.service_day, $scope.day.date, $scope.package.paxes); 

    } 
); 

Problem zaczyna się tutaj: żądanie dla tabeli usługi jest wywoływane dwukrotnie, gdy identyfikator service_id zmienia się tylko raz.

DLACZEGO, BÓG, DLACZEGO ?!

Jest kolejna część mojego kodu, gdzie, z PackageController, prowadzonym przez cały days_info tablicy i odczytuje wartość atrybutu price wewnątrz service.table: service.table.price. Tam zdaję sobie sprawę, że istnieją dwa zakresy: zakres: ten, który obsługuję, i drugi, który nie mam FREAKING IDEA, skąd pochodzi!

Jeśli wstawię console.log($scope); do metody, która przebiega przez days_info, otrzymam dwa zakresy dla każdego żądania. Ta metoda jest dostępna pod adresem PackageController.

Jakieś pomysły, dlaczego tak się dzieje?

PS: To moja pierwsza aplikacja angularjs, więc wziąć łatwy gdybym zawiedli się na czymś podstawowym ...

EDIT:

Jak wskazano przez kolegów po komentarzach, mój Pytanie nie było bardzo powtarzalne. Niestety, nie mogę tu umieścić tylko części, której mam wątpliwości, ponieważ nie mam najmniejszego pojęcia, gdzie leży problem! (Wiem, że to nie jest dużo pomocy)

zrobiłem kilka zrzutów ekranu z konsoli Chrome:

pierwszy requestions zwolniony na zmianę service_id

Request log for the service change (ordered by path name)

Jak widać, każde żądanie jest wywoływane dwukrotnie za każdym razem. To nie jest jednorazowa sprawa. Numer /api/service/{id}... jest wezwaniem do wyświetlenia informacji o tabeli usługi. /api/service/by_route/origin/... zwraca listę usług z jednego miasta do drugiego (lub tego samego). Jeden nie ingeruje w drugiego.

Drugi obraz jest wynikiem z console.log z zakresu kontrolnego PackageController $, w czasie, gdy identyfikator service_id jest zmieniany.

Scopes for the PackageController

Jak widać, istnieją dwa różne zakresy. Zakres b jest synem zakresu r. Zakres r dzwoni także do obserwatora na service_id?

Wezwanie za cenę sum jest nazywany dwukrotnie z differente miejscach, jak widać na obrazku poniżej:

Call Stack for the sumPrices method on PackageController

+3

Twoje pytanie jest za długie i zawiera wiele nieistotnych informacji, ale brakuje w nim powtarzalnego testu. Trudno zrozumieć, na czym polega problem. Ale dokumentacja mówi: * [...] W rzadkich przypadkach jest to niepożądane, ponieważ detektor jest wywoływany, gdy wynik funkcji watchExpression się nie zmienił. Aby wykryć ten scenariusz w odbiorniku fn, można porównać wartości newVal i oldVal. Jeśli te dwie wartości są identyczne (===), wówczas detektor został wywołany z powodu inicjalizacji. –

+5

Zazwyczaj używanie zegarka to zły pomysł. Jeśli nam powiesz, w prosty sposób, co chcesz osiągnąć, możemy pomóc Ci znaleźć lepszy sposób. –

+0

Porównuję dwie wartości (newValue i oldValue) w fn wywołanym po funkcji porównania. To nie wydaje się być problemem (już). Ponieważ funkcja jest systematycznie wywoływana dwa razy! Wstawię dwa wydruki z mojego logu sieciowego żądania i zakres prośby o zmianę usługi. –

Odpowiedz

3

Może rozwiązać problem. Nawet ja stawiam czoła dokładnie tak samo, jak wspomniałeś.

  1. Powodem dla mnie było to, że regulator był już ponownie zainicjowany i był tam osobny wywołanie API napisane w tym, który miał początkowo załadować stronę.

  2. Istnieje również scenariusz, w którym przypisano kontroler dwukrotnie w oznaczeniu.

+0

To było dokładnie to, co mi się przydarzyło! Nie otrzymałeś nagrody za 14 sekund. =/Przydzielono już Robertowi.Byłem deklaratorem 'ng-kontrolera' dla elementu div i wywoływaniem dyrektywy na tym samym kontrolerze, a więc utworzenie go dwa razy! To był problem. –

1
<div ng-repeat="day in package.days_info" class='row'> 
    <div class='col-md-12'> 
     <package-days-block day="day"></package-days-block> 
    </div> 
</div> 

<div class='container-fluid' ng-repeat='service in day.services'> 
    <service-block service="service"></service-block> 
</div> 

Przełęcz day i service dół do dyrektyw. Użyj wiązania dwukierunkowego, aby przekazać zmiany z day i service z powrotem do pakietu package.days_info.

Usunąć ServiceController Nie ma większego sensu powtarzanie kontrolera przez ng. <service-block> i <package-days-block> są dyrektywą E, która obsługuje logikę.

pisać tylko jeden obserwator w PackageController że oglądanie package.days_info Gdy day lub service zmiana, to może po prostu dowiedzieć się, i coś z tym zrobić.

Po prostu ochładzaj i napraw.

+0

Problem nie był dokładnie taki. Ale wskazówka była miła! Bardzo dobrze. Ponieważ prawdopodobnie będę go używał od teraz, dam ci nagrodę (i stracę ważność za 22 minuty). Wielkie dzięki. –

Powiązane problemy