2013-03-08 13 views
11

Zacznę od stwierdzenia, że ​​to, co próbuję zrobić, prawdopodobnie nie jest uważane za dobrą praktykę. Jednak muszę zrobić coś takiego, aby przenieść dużą aplikację internetową do AngularJs w małych krokach.Kątowa: Czy można oglądać zmienną globalną (tj. Poza zakresem)?

Próbowałem robić

$scope.$watch(function() { return myVar; }, function (n, old) { 
        alert(n + ' ' + old); 
       }); 

Gdzie myVar jest zmienną globalną (zdefiniowanej w oknie)

, po czym zmień MyVar z konsoli. Ale wystrzeliwuje się tylko przy pierwszym ustawieniu obserwatora.

To działa, jeśli mogę zaktualizować MyVar od wewnątrz regulatora (patrz http://jsfiddle.net/rasmusvhansen/vsDXz/3/, ale jeśli nie jest aktualizowany od jakiegoś spuścizny javascript

Czy istnieje jakiś sposób, aby to osiągnąć?

Aktualizacja lubię Odpowiedź Andersa, jeśli kod źródłowy jest całkowicie poza zasięgiem, jednak obecnie patrzę na to podejście, które wydaje się działać i nie włącza timera w co sekundę:

// In legacy code when changing stuff  
$('.angular-component').each(function() { 
     $(this).scope().$broadcast('changed'); 
}); 

// In angular 
$scope.$on('changed', function() { 
    $scope.reactToChange(); 
}); 

Naliczam punkty dla Andersa, mimo że pójdę z innym rozwiązaniem, ponieważ jego rozwiązanie poprawnie rozwiązuje wskazany problem.

+0

prawdopodobnie nie chce używać "każdego" do emisji, więc kątowy ma tylko jeden digest – charlietfl

+1

W swoim przykładowym kodzie, na co wskazywał element '.angular-component'? – mlhDev

+0

W moim przypadku wybrałem element, który faktycznie chciałem zmienić (używając 'angle.element (document.getElementById())' ponieważ nie używałem jQuery), a następnie nazwałem 'scope(). $ Broadcast ('customEventName'); '. Zauważ, że musiałem użyć '$ apply()' wewnątrz funkcji '$ on ('customEventName')', aby wywołać listę obserwatorów. –

Odpowiedz

12

Problem prawdopodobnie polega na tym, że modyfikujesz myVar spoza świata Angular. Angular nie uruchamia cyklów trawiennych/brudnych testów przez cały czas, tylko wtedy, gdy coś się dzieje w aplikacji, która powinna wywołać trawienie, na przykład zdarzenia DOM, o których Angular wie. Więc nawet jeśli zmienił się myVar, Angular nie widzi powodu, aby rozpocząć nowy cykl trawienia, ponieważ nic się nie stało (przynajmniej to, o czym wie Angular).

Aby więc zwolnić zegarek, musisz wymusić na Angularie, aby go przetrawić po zmianie myVar. Ale byłoby to trochę uciążliwe, myślę, że lepiej byłoby utworzyć obiekt obserwowalny globalnie, coś w tym stylu:

<!doctype html> 
<html ng-app="myApp"> 
<head> 
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script> 
    <script src="http://code.angularjs.org/1.0.5/angular.min.js"></script> 
    <script> 
    // Outside of Angular 
    window.myVar = {prop: "value1"}; 
    var myVarWatch = (function() { 
     var watches = {}; 

     return { 
      watch: function(callback) { 
       var id = Math.random().toString(); 
       watches[id] = callback; 

       // Return a function that removes the listener 
       return function() { 
        watches[id] = null; 
        delete watches[id]; 
       } 
      }, 
      trigger: function() { 
       for (var k in watches) { 
        watches[k](window.myVar); 
       } 
      } 
     } 
    })(); 

    setTimeout(function() { 
     window.myVar.prop = "new value"; 
     myVarWatch.trigger(); 
    }, 1000); 

    // Inside of Angular 
    angular.module('myApp', []).controller('Ctrl', function($scope) { 
     var unbind = myVarWatch.watch(function(newVal) { 
      console.log("the value changed!", newVal); 
     }); 

     // Unbind the listener when the scope is destroyed 
     $scope.$on('$destroy', unbind); 
    }); 
    </script> 
</head> 
<body ng-controller="Ctrl"> 

</body> 
</html> 
+1

Dzięki za wejście Anders, myślę, że jest to bardzo użyteczny sposób robienia tego, jeśli nie ma możliwości zmiany starszego kodu. Jestem w stanie wprowadzić małe zmiany w starym kodzie, więc myślę, że idę z innym podejściem (zobacz moją aktualizację). – rasmusvhansen

+1

Btw, sprawdź 'Object.observe()'. Pozwala na obserwowanie zmian na obiekcie. Nadal nie jest zaimplementowany w wielu przeglądarkach, ale są na nim różne rodzaje. –

+0

Potrzebowałem użyć $ scope. $ Zastosuj wewnątrz kątowego myVarWatch.watch, aby uzyskać kątowe przetrawienie zmian. – willJk

Powiązane problemy