In AngularJS konnten Sie Beobachter angeben, um Änderungen in Bereichsvariablen mithilfe der $watch
Funktion von zu beobachten $scope
. Was entspricht der Suche nach Variablenänderungen (z. B. in Komponentenvariablen) in Angular?
In AngularJS konnten Sie Beobachter angeben, um Änderungen in Bereichsvariablen mithilfe der $watch
Funktion von zu beobachten $scope
. Was entspricht der Suche nach Variablenänderungen (z. B. in Komponentenvariablen) in Angular?
Antworten:
In Angular 2 erfolgt die Änderungserkennung automatisch ... $scope.$watch()
und $scope.$digest()
RIP
Leider ist der Abschnitt "Änderungserkennung" des Entwicklungshandbuchs noch nicht geschrieben (es gibt einen Platzhalter am unteren Rand der Seite " Architekturübersicht " im Abschnitt "Das andere Zeug").
Hier ist mein Verständnis der Funktionsweise der Änderungserkennung:
setTimeout()
in unseren Komponenten etwas verwenden können, anstatt so etwas wie $timeout
... weil setTimeout()
Affen gepatcht sind.ChangeDetectorRef
.) Diese Änderungsdetektoren werden erstellt, wenn Angular Komponenten erstellt. Sie verfolgen den Status aller Ihrer Bindungen, um sie schmutzig zu überprüfen. Diese ähneln in gewissem Sinne der Automatik $watches()
, die Angular 1 für {{}}
Vorlagenbindungen einrichten würde .onPush
Änderungserkennungsstrategie für keine Ihrer Komponenten verwenden) wird jede Komponente im Baum einmal (TTL = 1) ... von oben in der Reihenfolge der Tiefe zuerst untersucht. (Wenn Sie sich im Entwicklungsmodus befinden, wird die Änderungserkennung zweimal ausgeführt (TTL = 2). Weitere Informationen hierzu finden Sie in ApplicationRef.tick () .) Mit diesen Änderungsdetektorobjekten werden alle Bindungen schmutzig überprüft.
ngOnChanges()
, um über Änderungen benachrichtigt zu werden. ngDoCheck()
(siehe diese SO Antwort für mehr dazu). Weitere Referenzen, um mehr zu erfahren:
onPush
.host
Dokumentation "Host Listener" im DirectiveMetadata API-Dokument . Es wird erklärt, wie globale Ereignisse innerhalb der Winkelzone abgehört werden (sodass die Änderungserkennung wie gewünscht ausgelöst wird). Diese Antwort hat einen funktionierenden Plunker.
Dieses Verhalten ist jetzt Teil des Komponentenlebenszyklus.
Eine Komponente kann die ngOnChanges-Methode in der OnChanges- Schnittstelle implementieren, um Zugriff auf Eingabeänderungen zu erhalten.
Beispiel:
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);
}
}
Wenn Sie zusätzlich zur automatischen bidirektionalen Bindung eine Funktion aufrufen möchten, wenn sich ein Wert ändert, können Sie die Syntax der bidirektionalen Bindungsverknüpfung auf die ausführlichere Version umstellen.
<input [(ngModel)]="yourVar"></input>
ist eine Abkürzung für
<input [ngModel]="yourVar" (ngModelChange)="yourVar=$event"></input>
(Siehe z. B. http://victorsavkin.com/post/119943127151/angular-2-template-syntax )
Sie könnten so etwas tun:
<input [(ngModel)]="yourVar" (ngModelChange)="changedExtraHandler($event)"></input>
Sie können getter function
oder get accessor
als Uhr auf Winkel 2 verwenden.
Siehe Demo hier .
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);
}
}
Hier ist ein anderer Ansatz, bei dem Getter- und Setter-Funktionen für das Modell verwendet werden.
@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;
}
}
(change)
jedem einzelnen Handler hinzufügen . Ich möchte nicht get|sets
jeder Eigenschaft in meinem Modell s hinzufügen . es wird nicht helfen, ein get|set
für hinzuzufügen this.object
; ngOnChanges()
erkennt nur Änderungen an @Input
s . Heiliges Manna! Was haben sie mit uns gemacht ??? Geben Sie uns eine Art Deep Watch zurück!
Wenn Sie es in [(yourVar)]
beide Richtungen binden möchten, können Sie es verwenden , müssen es jedoch implementierenyourVarChange
es in beide Ereignis und es jedes Mal aufrufen, wenn sich Ihre Variable ändert.
So etwas, um den Heldenwechsel zu verfolgen
@Output() heroChange = new EventEmitter();
und wenn sich dein Held umzieht, ruf an this.heroChange.emit(this.hero);
Die [(hero)]
Bindung erledigt den Rest für Sie
siehe Beispiel hier:
Versuchen Sie dies, wenn Ihre Anwendung weiterhin Anforderungen $parse
stellt $eval
, z. $watch
B. das Verhalten in Angular
Dies beantwortet die Frage nicht direkt, aber ich bin bei verschiedenen Gelegenheiten auf diese Stapelüberlauffrage gestoßen, um etwas zu lösen, für das ich $ watch in angleJs verwenden würde. Am Ende habe ich einen anderen Ansatz als in den aktuellen Antworten beschrieben gewählt und möchte ihn teilen, falls jemand ihn nützlich findet.
Die Technik, mit der ich etwas Ähnliches erreiche, $watch
besteht darin, ein BehaviorSubject
( mehr zum Thema hier ) in einem Angular-Dienst zu verwenden und meine Komponenten es abonnieren zu lassen, um die Änderungen zu erhalten (zu beobachten). Dies ähnelt a $watch
in angleJs, erfordert jedoch etwas mehr Einrichtung und Verständnis.
In meiner Komponente:
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;
});
}
}
In meinem Dienst
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});
}
}
Hier ist eine Demo zu Stackblitz