AngularJS'de $ scope. $ Watch ve $ scope. $ Nasıl kullanılır?


1088

Nasıl kullanılacağını anlamıyorum $scope.$watchve $scope.$apply. Resmi belgeler yardımcı olmuyor.

Özellikle anlamadıklarım:

  • DOM'a bağlılar mı?
  • Modelde DOM değişikliklerini nasıl güncelleyebilirim?
  • Aralarındaki bağlantı noktası nedir?

Bu öğreticiyi denedim , ancak anlaşılması $watchve $applykabul edilmesi gerekiyor.

Ne yapar $applyve $watchyapar, onları nasıl uygun şekilde kullanabilirim?

Yanıtlar:


1737

AngularJS'nin bunu anlamak için nasıl çalıştığını bilmeniz gerekir.

Özet döngüsü ve $ kapsam

Her şeyden önce, AngularJS sindirim döngüsü olarak adlandırılan bir kavram tanımlar . Bu döngü, AngularJS'nin tüm s tarafından izlenen tüm değişkenlerde herhangi bir değişiklik olup olmadığını kontrol ettiği bir döngü olarak düşünülebilir $scope. Eğer varsa Yani $scope.myVarsizin denetleyici tanımlanan ve bu değişken edildi izlenen için işaretlenmiş , o zaman dolaylı üzerindeki değişiklikleri izlemek için angularjs anlatıyorsun myVardöngünün her tekrarında.

Doğal bir takip sorusu şu olabilir: Her şey $scopeizlenmeye bağlı mı ? Neyse ki hayır. Bilgisayarınızdaki her nesnede yapılan değişiklikleri izlerseniz $scope, hızlı bir şekilde özetleme döngüsünün değerlendirilmesi çok uzun sürer ve hızlı bir şekilde performans sorunlarıyla karşılaşırsınız. Bu yüzden AngularJS ekibi bize bazı $scopedeğişkenlerin izlendiğini bildirmenin iki yolunu verdi (aşağıda okuyun).

$ watch, $ kapsam değişikliklerini dinlemeye yardımcı olur

Bir $scopedeğişkeni izlendiğini bildirmenin iki yolu vardır .

  1. İfadeyle şablonunuzda kullanarak <span>{{myVar}}</span>
  2. $watchServis aracılığıyla manuel olarak ekleyerek

Reklam 1) Bu en yaygın senaryodur ve eminim daha önce görmüştünüz, ancak bunun arka planda bir saat oluşturduğunu bilmiyordunuz. Evet, vardı! AngularJS yönergelerinin (örneğin ng-repeat) kullanılması örtülü saatler de oluşturabilir.

Reklam 2) Kendi saatlerinizi bu şekilde yaratabilirsiniz . $watchhizmet, ekli bir değer $scopedeğiştiğinde bazı kodları çalıştırmanıza yardımcı olur . Nadiren kullanılır, ancak bazen yardımcı olur. Örneğin, 'myVar' her değiştiğinde bir kod çalıştırmak isterseniz, aşağıdakileri yapabilirsiniz:

function MyController($scope) {

    $scope.myVar = 1;

    $scope.$watch('myVar', function() {
        alert('hey, myVar has changed!');
    });

    $scope.buttonClicked = function() {
        $scope.myVar = 2; // This will trigger $watch expression to kick in
    };
}

$ Apply, değişikliklerin özet döngüsüne entegre edilmesini sağlar

$applyFonksiyonu bir entegrasyon mekanizması olarak düşünebilirsiniz . Gördüğünüz gibi, doğrudan nesneye bağlı$scope bazı izlenen değişkenleri her değiştirdiğinizde , AngularJS değişikliğin olduğunu bilecektir. Çünkü AngularJS bu değişiklikleri izlemeyi zaten biliyordu. Dolayısıyla, çerçeve tarafından yönetilen kodda gerçekleşirse, sindirim döngüsü devam eder.

Ancak, bazen AngularJS dünyasının dışında bir değer değiştirmek ve değişikliklerin normal olarak yayıldığını görmek istersiniz . Bunu düşünün - $scope.myVarbir jQuery $.ajax()işleyicisi içinde değiştirilecek bir değeriniz var . Bu gelecekte bir noktada olacak. AngularJS bunun gerçekleşmesini bekleyemez, çünkü jQuery'de beklemesi talimatı verilmemiştir.

Bununla başa çıkmak $applyiçin tanıtıldı. Sindirim döngüsünü açıkça başlatmanızı sağlar. Ancak, bunu yalnızca bazı verileri AngularJS'ye (diğer çerçevelerle entegrasyon) geçirmek için kullanmalısınız, ancak bu yöntemi asla AngularJS bir hata atacağından normal AngularJS koduyla birlikte kullanmayın.

Tüm bunlar DOM ile nasıl ilişkilidir?

Eh, şimdi tüm bunları biliyorsunuz, gerçekten öğretici tekrar takip etmelisiniz. Özet döngüsü, $scopehiçbir şeye bağlı olmayan tüm izleyicileri hiçbir şey değişmediği sürece değerlendirerek kullanıcı arayüzünün ve JavaScript kodunun senkronize kalmasını sağlar . Özet döngüsünde başka değişiklik olmazsa, iş bitmiş sayılır.

Nesneleri $scopeaçık bir şekilde Denetleyici'de veya {{expression}}doğrudan görünümde formda bildirerek nesneye ekleyebilirsiniz .

Umarım tüm bunlar hakkında bazı temel bilgileri açıklığa kavuşturur.

Diğer okumalar:


57
"Açısal tüm $ kapsamlarına bağlı tüm değişkenlerde herhangi bir değişiklik olup olmadığını kontrol eder" - Bunun doğru olduğunu düşünmüyorum. Ben sadece açısal (kirli) $ saatler kurulmuş $ kapsam özelliklerini kontrol inanıyorum (bir görünümde {{}} kullanmanın otomatik olarak bir $ izle oluşturacağını unutmayın). Ayrıca, Kapsam sayfasındaki "Scope $ watch Performansı Etkileyen Koşullar" bölümüne bakın .
Mark Rajcok

5
Durum böyle olabilir. Bununla ilgili daha fazla bilgi edinmek ve cevabımı düzenlemek için biraz zaman bulmaya çalışacağım.
ŁukaszBachman

15
@ MarkRajcok, haklıydın. Cevabımı değiştirdim ve bunun nasıl uygulandığını gösteren bir makaleye dikkat çektim.
ŁukaszBachman

3
bunu kullanmaya ne dersin? ("Control as" yöntemi)
Leandro

2
"Kontrol şekli" kullanmanın yukarıdaki bilgiler üzerinde hiçbir etkisi olmamalıdır. This.myVar kullanmak myVar'ı kapsama alır.
Marcus Rådell

161

AngularJS'de modellerimizi güncelliyoruz ve görünümlerimiz / şablonlarımız DOM'u "otomatik olarak" (yerleşik veya özel yönergeler aracılığıyla) güncelliyor.

$ Apply ve $ watch (her ikisi de Scope yöntemi) DOM ile ilişkili değildir.

Kavramlar sayfası (bölüm "Runtime") $ sindirmek döngünün oldukça iyi bir açıklama, $ uygulamak, $ evalAsync kuyruğu ve $ izle listesi vardır. İşte metne eşlik eden resim:

$ özet döngüsü

Kodun bir kapsama erişimi olan her ne olursa olsun - normalde denetleyiciler ve yönergeler (bağlantı işlevleri ve / veya denetleyicileri) - AngularJS'nin bu kapsama göre değerlendireceği bir " watchExpression " oluşturabilir. Bu değerlendirme AngularJS, $ digest döngüsüne (özellikle "$ watch list" döngüsüne) girdiğinde gerçekleşir. Bireysel kapsam özelliklerini izleyebilir, iki özelliği birlikte izlemek için bir işlev tanımlayabilir, bir dizinin uzunluğunu izleyebilirsiniz, vb.

İşler "AngularJS içinde" olduğunda - örneğin, AngularJS iki yönlü veri bağlama özelliğinin etkin olduğu (yani ng-modelini kullanan), $ http geri arama yangınları vb. İçeren bir metin kutusuna yazarsınız. yukarıdaki şekilde "AngularJS" dikdörtgenin içindedir. Tüm watchExpressions değerlendirilecektir (muhtemelen bir kereden fazla - başka değişiklik algılanana kadar).

İşler "AngularJS dışında" olduğunda - örneğin, bir yönergede bind () yöntemini kullandınız ve sonra o olay tetiklendi ve geri çağrınızın çağrılması veya bazı jQuery kayıtlı geri çağrı yangınları oluşuyor - hala "Native" dikdörtgenindeyiz. Geri arama kodu herhangi bir $ saatinin izlediği herhangi bir şeyi değiştirirse, $ digest döngüsünün çalışmasına neden olan AngularJS dikdörtgeni içine girmek için $ Apply öğesini çağırır ve bu nedenle AngularJS değişikliği fark eder ve sihrini yapar.


5
Fikri anlıyorum, anlamadığım şey verinin gerçekte nasıl aktarıldığı. Çok fazla veri ile bir nesne olan bir model var, ben DOM manipüle için bazı kullanın. sonra bazıları değişti. Değiştirilen verileri modelde doğru yere nasıl koyabilirim? Kullandığım örnekte manipülasyon yapıyor ve sonunda sadece kullanıyor scope.$apply(scope.model), hangi verilerin aktarıldığını ve modelde doğru yere nasıl aktarıldığını anlamıyorum?
ilyo

6
Büyülü bir veri aktarımı gerçekleşmez. Normalde Açısal uygulamalarda, görünümü / DOM güncellemelerini yönlendiren Açısal modelleri değiştirmeniz gerekir. DOM'u Angular dışında güncellerseniz modelleri manuel olarak güncellemeniz gerekir. Açısal ifade olarak scope.$apply(scope.model)değerlendirilir scope.modelve ardından $ digest döngüsü girilir. Referans verdiğiniz makalede scope.$apply(), model zaten izlendiğinden muhtemelen yeterli olacaktır. Stop () işlevi modeli güncelliyor (Bence toUpdate scope.model için bir başvuru olduğuna inanıyorum) ve sonra $ Apply denir.
Mark Rajcok

AngularJS dokümanları bu cevabın altından kaymış gibi görünüyor (ilk bağlantının "çalışma zamanı" veya $watchsayfa yok ve ikinci bağlantı bozuldu - şu andan itibaren, her neyse). Acı verici bir şekilde, arşiv sürümleri içeriği ne zaman eşzamansız oluşturduysa önbelleğe almadı.
Ocak'ta

52

AngularJS, bu olaylar döngüsünü genişleterek adlı bir şey oluşturur AngularJS context.

) (İzle $

Kullanıcı arayüzünde her şey bağladığınızda $watchbir $watchlisteye bir eklersiniz .

User: <input type="text" ng-model="user" />
Password: <input type="password" ng-model="pass" />

Burada $scope.user, birinci girdiye $scope.passbağlı olan ve ikincisine bağlı olan var . Bunu $watchyaparak $watchlisteye iki es ekliyoruz .

Bizim zaman şablon yüklendiğinde, AKA bağlama aşamasında, derleyici her direktif aramaya ve tüm yaratır edecek $watchihtiyaç vardır es.

Angularjs sağlar $watch, $watchcollectionve $watch(true). Aşağıda, gözetmenlerden üçünü de derinlemesine açıklayan düzgün bir diyagram bulunmaktadır .

Resim açıklamasını buraya girin

angular.module('MY_APP', []).controller('MyCtrl', MyCtrl)
function MyCtrl($scope,$timeout) {
  $scope.users = [{"name": "vinoth"},{"name":"yusuf"},{"name":"rajini"}];

  $scope.$watch("users", function() {
    console.log("**** reference checkers $watch ****")
  });

  $scope.$watchCollection("users", function() {
    console.log("**** Collection  checkers $watchCollection ****")
  });

  $scope.$watch("users", function() {
    console.log("**** equality checkers with $watch(true) ****")
  }, true);

  $timeout(function(){
     console.log("Triggers All ")
     $scope.users = [];
     $scope.$digest();

     console.log("Triggers $watchCollection and $watch(true)")
     $scope.users.push({ name: 'Thalaivar'});
     $scope.$digest();

     console.log("Triggers $watch(true)")
     $scope.users[0].name = 'Superstar';
     $scope.$digest();
  });
}

http://jsfiddle.net/2Lyn0Lkb/

$digest döngü

Tarayıcı AngularJS bağlamı tarafından yönetilebilen bir olay aldığında, $digestdöngü tetiklenir. Bu döngü iki küçük döngüden yapılır. Biri $evalAsynckuyruğu, diğeri ise kuyruğu işler $watch list. $digestListesinde bir şekilde döngü $watchsahip olduğumuz

app.controller('MainCtrl', function() {
  $scope.name = "vinoth";

  $scope.changeFoo = function() {
      $scope.name = "Thalaivar";
  }
});

{{ name }}
<button ng-click="changeFoo()">Change the name</button>

Burada sadece bir tane var $watchçünkü ng-click saat oluşturmuyor.

Düğmeye basıyoruz.

  1. Tarayıcı, AngularJS bağlamına girecek bir olay alır
  2. $digestDöngü çalışacak ve değişiklikler için her $ saatini soracaktır.
  3. Yana $watch$ scope.name değişiklikler için izliyordum hangi bir değişiklik raporları, başka zorlayacaktır $digestdöngü.
  4. Yeni döngü hiçbir şey rapor etmiyor.
  5. Tarayıcı kontrolü geri alır ve DOM'u, yeni scope scope.name değerini yansıtacak şekilde güncelleyecektir.
  6. Burada önemli olan, AngularJS bağlamına giren HER olayın bir $digestdöngü çalıştırmasıdır . Bu, bir girişe her mektup yazdığımızda, döngünün $watchbu sayfadaki her birini kontrol etmeye çalışacağı anlamına gelir .

$ Uygulamak ()

Bir $applyolay tetiklendiğinde çağırırsanız , açısal bağlamdan geçer, ancak çağırmazsanız bunun dışında çalışır. Bu kadar kolay. döngüyü dahili olarak $applyarayacak$digest() ve DOM'un yeni güncellenen değerle güncellendiğinden emin olmak için tüm saatler üzerinde yineleme yapacaktır.

$apply()Yöntem tüm ilgili izleyici tetikler $scopeise zincir $digest()yöntemi, yalnızca güncel izleyici tetikler $scopeve onun children. Yüksek $scopenesnelerin hiçbirinin yerel değişiklikler hakkında bilgi sahibi olması gerekmediğinde kullanabilirsiniz $digest().


18

Hangi kapak çok derinlemesine videoları bulduk $watch, $apply, $digestve de döngüleri sindirmek:

Aşağıda, bu videolarda kavramları açıklamak için kullanılan birkaç slayt vardır (her iki durumda da, yukarıdaki bağlantılar kaldırılırsa / çalışmıyorsa).

Resim açıklamasını buraya girin

Yukarıdaki görüntüde, "$ scope.c" hiçbir veri bağlamasında (işaretlemede) kullanılmadığı için izlenmemektedir. Diğer ikisi ( $scope.ave $scope.b) izlenecek.

Resim açıklamasını buraya girin

Yukarıdaki görüntüden: İlgili tarayıcı olayına bağlı olarak, AngularJS olayı yakalar, özet döngüsünü gerçekleştirir (değişikliklerin tüm saatlerinde geçer), izleme işlevlerini yürütür ve DOM'u günceller. Değilse tarayıcı olaylar, özet döngüsü elle kullanılarak tetiklenebilir $applyveya $digest.

Hakkında daha fazla $applyve $digest:

Resim açıklamasını buraya girin


17

Orada $watchGroupve $watchCollectionde. Özellikle, $watchGrouptuval, WebGL veya sunucu isteğindeki başka bir görünüm için, dom nesnesi olmayan bir görünümde birden çok özelliği olan bir nesneyi güncellemek için bir işlevi çağırmak istiyorsanız gerçekten yararlıdır .

İşte, belge bağlantısı .


Hakkında yorum yapardım $watchCollectionama zaten yaptığını görüyorum. İşte bu konuda AngularJS sitesinden belgeler . $watchDerinliğin çok güzel bir görüntüsünü sağlarlar . Bilgilerin sayfanın altına yakın olduğuna dikkat edin.
JabberwockyDecompiler

15

Sadece TÜM yukarıda, sıkıcı ve uykulu okuma bitirmek (üzgünüm ama doğrudur). Çok teknik, derinlemesine, ayrıntılı ve kuru. Neden yazıyorum? AngularJS çok büyük olduğu için birbirine bağlı birçok kavram, herkesin çıldırmasına neden olabilir. Sık sık kendime sordum, onları anlayacak kadar akıllı değil miyim? Hayır! Çünkü çok azı teknolojiyi tüm terminolojiler olmadan bir kukla dilinde açıklayabilir ! Tamam, deneyeyim:

1) Hepsi olay güdümlü şeyler. (Gülüşleri duyuyorum, ama okumaya devam et)

Olaya dayalı ne olduğunu bilmiyorsanız, o zaman sayfaya bir düğme yerleştirdiğinizi düşünün, kullanıcıların üzerine tıkladığınız eylemleri tetiklemek için "tıkladığında" kullanarak bir işlev olmadan bağlayın. işlevi. Veya SQL Server / Oracle "tetik" düşünün.

2) $ watch "tıklandığında".

Özel olan, parametre olarak 2 işlevi almasıdır, birincisi olaydan değer verir, ikincisi değeri dikkate alır ...

3) $ digest, yorulmadan kontrol eden patron , bla-bla-bla ama iyi bir patron.

4) $ Apply, bir hataya dayanıklı gibi manuel olarak yapmak istediğinizde size yol verir (tıklama tıklaması durumunda, çalışmaya zorlarsınız.)

Şimdi, onu görselleştirelim. Fikri almayı daha da kolaylaştırmak için bunu hayal edin:

Bir restoranda,

- Garsonlar

Müşterilerden sipariş almaları gerekiyor, bu

$watch(
  function(){return orders;},
  function(){Kitchen make it;}
);

- Tüm garsonların uyanık olduğundan emin olmak için MÜDÜR koşuyor, müşterilerin herhangi bir değişiklik belirtisine yanıt veriyor. Bu$digest()

- SAHİBİN , istek üzerine herkesi yönlendirecek en üst güce sahiptir, bu$apply()


2
Bu 5 yaşındaki bir kişi tarafından anlaşılabilir. Bu tür bir cevabı takdir ediyorum. +1
Chris22
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.