AngularJS $ saatine Angular eşdeğeri nedir?


Yanıtlar:


268

Açısal 2'de değişiklik algılama otomatiktir ... $scope.$watch()ve $scope.$digest()RIP

Maalesef, geliştirici kılavuzunun Değişiklik Algılama bölümü henüz yazılmamıştır ( Mimariye Genel Bakış sayfasının altında, "Diğer Öğeler" bölümünde bir yer tutucu vardır ).

Değişiklik algılamanın nasıl çalıştığını anlayacağım:

  • Zone.js "maymun dünyayı yamalar" - tarayıcıdaki tüm zaman uyumsuz API'ları durdurur (Angular çalıştığında). Bu yüzden, setTimeout()bizim gibi yamalar gibi bir şeyden ziyade bileşenlerimizde kullanabiliriz $timeoutçünkü setTimeout()maymun yamalı.
  • Açısal bir "değişim dedektörleri" ağacı oluşturur ve bakımını yapar. Bileşen / yönerge başına böyle bir değişiklik detektörü (sınıf) vardır. (Enjekte ederek bu nesneye erişebilirsiniz ChangeDetectorRef.) Bu değişiklik dedektörleri, Angular bileşenler oluşturduğunda oluşturulur. Kirli kontrol için, tüm bağlantılarınızın durumunu takip ederler. Bunlar, bir anlamda, $watches()Açısal 1'in {{}}şablon bağlamaları için ayarlayacağı otomatikliğe benzer .
    Açısal 1'den farklı olarak, değişiklik algılama grafiği yönlendirilmiş bir ağaçtır ve döngüleri olamaz (bu, aşağıda göreceğimiz gibi Açısal 2'yi çok daha performanslı hale getirir).
  • Bir olay tetiklendiğinde (Açısal bölge içinde), yazdığımız kod (olay işleyici geri araması) çalışır. İstediği verileri güncelleyebilir - paylaşılan uygulama modeli / durumu ve / veya bileşenin görünüm durumu.
  • Bundan sonra, Zone.js'nin eklediği kancalar nedeniyle Angular'ın değişiklik algılama algoritmasını çalıştırır. Varsayılan olarak (yani, onPushbileşenlerinizin hiçbirinde değişiklik algılama stratejisini kullanmıyorsanız ), ağaçtaki her bileşen bir kez (TTL = 1) ... üstten, derinlik-birinci sırayla incelenir. ( Geliştirme modundaysanız değişiklik algılama iki kez çalışır (TTL = 2). Bunun hakkında daha fazla bilgi için ApplicationRef.tick () öğesine bakın .) Bu değişiklik dedektörü nesnelerini kullanarak tüm bağlantılarınızda kirli denetim gerçekleştirir.
    • Yaşam döngüsü kancaları, değişiklik algılamanın bir parçası olarak adlandırılır.
      İzlemek istediğiniz bileşen verileri ilkel bir girdi özelliğiyse (Dize, boole, sayı), ngOnChanges()değişikliklerden haberdar olmak için uygulayabilirsiniz .
      İnput özelliği bir başvuru türüyse (nesne, dizi vb.), Ancak başvuru değişmediyse (örneğin, varolan bir diziye bir öğe eklediniz), uygulamanız gerekir ngDoCheck()( daha fazla bilgi için bu SO yanıtına bakın) bu).
      Bileşenin özelliklerini ve / veya alt öğe bileşenlerinin özelliklerini değiştirmelisiniz (çünkü tek ağaç yürüyüşü uygulaması - yani tek yönlü veri akışı). İşte bunu ihlal eden bir dalgıç . Durumsal borular sizi buraya da açabilir .
  • Bulunan tüm bağlayıcı değişiklikler için Bileşenler güncelleştirilir ve ardından DOM güncelleştirilir. Değişiklik tespiti artık tamamlanmıştır.
  • Tarayıcı DOM değişikliklerini fark eder ve ekranı günceller.

Daha fazla bilgi için diğer referanslar:


window.addEventListener () değişkeni değiştirdiğinde algılamayı tetiklemez ... beni çıldırtır, üzerinde hiçbir şey yoktur.
Albert James Teddy

@AlbertJamesTeddy, DirectiveMetadata APIhost belgesindeki "Ana Bilgisayar Dinleyicileri" belgelerine bakın . Açısal bölgenin içinden küresel olayların nasıl dinleneceğini açıklar (böylece değişiklik algılaması istenildiği gibi tetiklenir). Bu cevabın çalışan bir dalma pistonu var.
Mark Rajcok

bu bağlantı yardımcı olacaktır ..
refactor

@MarkRajcok, değişiklik algılama hakkındaki makaleme referans ekleme özgürlüğü aldım. Umursamıyorsun. Kaputun altında ne olduğunu çok ayrıntılı olarak açıklıyor.
Max Koretskyi

Tek yönlü veri akışı kuralını ihlal eden plunkr ile ilgili olarak, plunkr'ı enableProdMode () ile çalıştırırsanız, değişiklik algılayıcı yalnızca bir kez çalıştığından, üst görünümde herhangi bir güncelleme görmeyeceğinizi eklemek isterim.
Mister_L

93

Bu davranış, artık bileşen yaşam döngüsünün bir parçasıdır.

Bir bileşen, giriş değişikliklerine erişmek için OnChanges arabiriminde ngOnChanges yöntemini uygulayabilir .

Misal:

import {Component, Input, OnChanges} from 'angular2/core';


@Component({
  selector: 'hero-comp',
  templateUrl: 'app/components/hero-comp/hero-comp.html',
  styleUrls: ['app/components/hero-comp/hero-comp.css'],
  providers: [],
  directives: [],

  pipes: [],
  inputs:['hero', 'real']
})
export class HeroComp implements OnChanges{
  @Input() hero:Hero;
  @Input() real:string;
  constructor() {
  }
  ngOnChanges(changes) {
      console.log(changes);
  }
}

77
bu sadece @Input () için geçerlidir. bileşeninizin kendi verilerindeki değişiklikleri izlemek istiyorsanız, bu işe yaramaz
LanderV

4
Basit değişkenlerde değişiklik alamadım (örneğin boole). Yalnızca nesne değişiklikleri algılanır.
mtoloo

Neden bileşenin dekoratörüne "girişler" dizisi eklemeniz gerekiyor? değişiklik tespiti de bu olmadan çalışacaktır.
Gil Epshtain

68

Otomatik iki yönlü ciltlemeye ek olarak, bir değer değiştiğinde bir işlevi çağırmak istiyorsanız, iki yönlü ciltleme kısayol sözdizimini daha ayrıntılı sürüme bölebilirsiniz.

<input [(ngModel)]="yourVar"></input>

için kestirme

<input [ngModel]="yourVar" (ngModelChange)="yourVar=$event"></input>

(bkz. http://victorsavkin.com/post/119943127151/angular-2-template-syntax )

Böyle bir şey yapabilirsiniz:

<input [(ngModel)]="yourVar" (ngModelChange)="changedExtraHandler($event)"></input>


Son örnekte ngModel?
Eugene Kulabuhov

16

Açısal 2'de saat olarak hareket etmek için getter functionveya tuşunu kullanabilirsiniz get accessor.

Demoyu buradan görebilirsiniz .

import {Component} from 'angular2/core';

@Component({
  // Declare the tag name in index.html to where the component attaches
  selector: 'hello-world',

  // Location of the template for this component
  template: `
  <button (click)="OnPushArray1()">Push 1</button>
  <div>
    I'm array 1 {{ array1 | json }}
  </div>
  <button (click)="OnPushArray2()">Push 2</button>
  <div>
    I'm array 2 {{ array2 | json }}
  </div>
  I'm concatenated {{ concatenatedArray | json }}
  <div>
    I'm length of two arrays {{ arrayLength | json }}
  </div>`
})
export class HelloWorld {
    array1: any[] = [];
    array2: any[] = [];

    get concatenatedArray(): any[] {
      return this.array1.concat(this.array2);
    }

    get arrayLength(): number {
      return this.concatenatedArray.length;
    }

    OnPushArray1() {
        this.array1.push(this.array1.length);
    }

    OnPushArray2() {
        this.array2.push(this.array2.length);
    }
}

12

İşte model için alıcı ve ayarlayıcı işlevlerini kullanan başka bir yaklaşım.

@Component({
  selector: 'input-language',
  template: `
  …
  <input 
    type="text" 
    placeholder="Language" 
    [(ngModel)]="query" 
  />
  `,
})
export class InputLanguageComponent {

  set query(value) {
    this._query = value;
    console.log('query set to :', value)
  }

  get query() {
    return this._query;
  }
}

4
Bu konu delilik. Karmaşık bir forma bağlı birçok özelliği olan bir nesne var . (change)Bunların her birine işleyici eklemek istemiyorum ; Modelimdeki get|setsher mülke s eklemek istemiyorum ; Bir eklemek için yardımcı olmaz get|setiçin this.object; ngOnChanges() Yalnızca değişiklikleri algılar @Inputs . Kutsal manna! Bize ne yaptılar ??? Bize bir tür derin gözlem verin!
Cody

6

Bunu 2 yönlü bağlama yapmak istiyorsanız, kullanabilirsiniz [(yourVar)], ancak yourVarChangeolayı uygulamanız ve değişken değişikliğiniz her seferinde çağırmanız gerekir.

Kahraman değişimini izlemek için böyle bir şey

@Output() heroChange = new EventEmitter();

ve sonra kahramanınız değiştiğinde, this.heroChange.emit(this.hero);

[(hero)]sizin için dinlenme yapacak bağlama

buradaki örneğe bakın:

http://plnkr.co/edit/efOGIJ0POh1XQeRZctSx?p=preview



2

Bu doğrudan soruyu cevaplamıyor, ama ben angularJs $ watch için kullanacağım bir şeyi çözmek için bu Stack Overflow sorusuna indi farklı durumlarda var. Son olarak, mevcut cevaplarda açıklanandan başka bir yaklaşım kullandım ve birisinin yararlı bulması durumunda bunu paylaşmak istiyorum.

Benzer bir şey başarmak için kullandıkları tekniği $watchbir kullanmaktır BehaviorSubject( burada konu hakkında daha fazla bir Açısal hizmetinde) ve benim bileşenleri değişiklikleri (izlemek) almak için abone izin verin. Bu, $watchaçısalJ'lere benzer , ancak biraz daha kurulum ve anlayış gerektirir.

Bileşenimde:

export class HelloComponent {
  name: string;
  // inject our service, which holds the object we want to watch.
  constructor(private helloService: HelloService){
    // Here I am "watching" for changes by subscribing
    this.helloService.getGreeting().subscribe( greeting => {
      this.name = greeting.value;
    });
  }
}

Hizmetimde

export class HelloService {
  private helloSubject = new BehaviorSubject<{value: string}>({value: 'hello'});
  constructor(){}
  // similar to using $watch, in order to get updates of our object 
  getGreeting(): Observable<{value:string}> {
    return this.helloSubject;
  }
  // Each time this method is called, each subscriber will receive the updated greeting.
  setGreeting(greeting: string) {
    this.helloSubject.next({value: greeting});
  }
}

İşte Stackblitz hakkında bir demo

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.