W AngularJS można było określić obserwatorów, którzy będą obserwować zmiany zmiennych zakresu za pomocą $watch
funkcji $scope
. Jaki jest odpowiednik obserwowania zmian zmiennych (na przykład zmiennych składowych) w Angular?
W AngularJS można było określić obserwatorów, którzy będą obserwować zmiany zmiennych zakresu za pomocą $watch
funkcji $scope
. Jaki jest odpowiednik obserwowania zmian zmiennych (na przykład zmiennych składowych) w Angular?
Odpowiedzi:
W Angular 2 wykrywanie zmian odbywa się automatycznie ... $scope.$watch()
i $scope.$digest()
RIP
Niestety sekcja Wykrywanie zmian w przewodniku dla deweloperów nie została jeszcze napisana (w dolnej części strony Przegląd architektury znajduje się symbol zastępczy , w sekcji „Inne rzeczy”).
Oto moje rozumienie działania detekcji zmian:
setTimeout()
wewnątrz naszych komponentów zamiast czegoś takiego jak $timeout
... ponieważ setTimeout()
jest załatany małpą.ChangeDetectorRef
.) Te detektory zmian są tworzone, gdy Angular tworzy komponenty. Śledzą stan wszystkich twoich powiązań, w celu brudnego sprawdzania. W pewnym sensie są one podobne do automatycznych $watches()
ustawień Angulara 1 dla {{}}
powiązań szablonów. onPush
strategii wykrywania zmian na żadnym ze swoich komponentów), każdy element w drzewie jest sprawdzany raz (TTL = 1) ... od góry, w kolejności od głębokości do pierwszej. (Cóż, jeśli jesteś w trybie deweloperskim, wykrywanie zmian działa dwa razy (TTL = 2). Więcej informacji na ten temat znajdziesz w ApplicationRef.tick () .) Wykonuje sprawdzanie wszystkich powiązań przy użyciu tych obiektów wykrywacza zmian.
ngOnChanges()
aby otrzymywać powiadomienia o zmianach. ngDoCheck()
(patrz to tak odpowiedź na dłużej na to). Inne odniesienia, aby dowiedzieć się więcej:
onPush
.host
dokumentacją „Host nasłuchiwania” w dokumentacji interfejsu API dyrektywy Metadata . Wyjaśnia, jak słuchać globalnych wydarzeń z wewnątrz strefy kątowej (więc wykrywanie zmian będzie uruchamiane zgodnie z potrzebami). Ta odpowiedź ma działającego plunkera.
To zachowanie jest teraz częścią cyklu życia komponentu.
Komponent może zaimplementować metodę ngOnChanges w interfejsie OnChanges , aby uzyskać dostęp do zmian danych wejściowych.
Przykład:
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);
}
}
Jeśli oprócz automatycznego wiązania dwukierunkowego chcesz wywołać funkcję, gdy zmienia się wartość, możesz przerwać składnię skrótu wiązania dwustronnego do wersji bardziej szczegółowej.
<input [(ngModel)]="yourVar"></input>
jest skrótem od
<input [ngModel]="yourVar" (ngModelChange)="yourVar=$event"></input>
(patrz np. http://victorsavkin.com/post/119943127151/angular-2-template-syntax )
Możesz zrobić coś takiego:
<input [(ngModel)]="yourVar" (ngModelChange)="changedExtraHandler($event)"></input>
Możesz używać getter function
lub get accessor
działać jako zegarek na kanciastym 2.
Zobacz demo tutaj .
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);
}
}
Oto inne podejście wykorzystujące funkcje gettera i settera dla modelu.
@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)
programów obsługi do każdego z nich; Nie chcę dodawać get|sets
s do każdej właściwości w moim modelu; to nie pomoże, aby dodać get|set
do this.object
; ngOnChanges()
wykrywa tylko zmiany w @Input
s . Święta manna! Co oni nam zrobili ??? Oddaj nam jakiś rodzaj głębokiej obserwacji!
Jeśli chcesz uczynić to wiązaniem dwukierunkowym, możesz użyć [(yourVar)]
, ale musisz zaimplementować yourVarChange
zdarzenie i wywołać je za każdym razem, gdy zmieniasz zmienną.
Coś takiego do śledzenia zmiany bohatera
@Output() heroChange = new EventEmitter();
a potem, gdy twój bohater się zmieni, zadzwoń this.heroChange.emit(this.hero);
[(hero)]
wiążące zrobi resztę za Ciebie
patrz przykład tutaj:
Spróbuj tego, gdy aplikacja nadal żąda $parse
, $eval
, $watch
jak zachowanie w kątowym
To nie odpowiada bezpośrednio na pytanie, ale przy różnych okazjach padałem na to pytanie dotyczące przepełnienia stosu, aby rozwiązać coś, czego użyłbym $ watch w angularJs. Skończyło się na innym podejściu niż opisano w bieżących odpowiedziach i chcę się nim podzielić, na wypadek, gdyby ktoś uznał to za przydatne.
Techniką, której używam, aby osiągnąć coś podobnego, $watch
jest użycie BehaviorSubject
( więcej na ten temat tutaj ) w usłudze Angular i pozwolenie moim komponentom na subskrypcję, aby uzyskać (obserwować) zmiany. Jest to podobne do $watch
w angularJs, ale wymaga nieco więcej konfiguracji i zrozumienia.
W moim komponencie:
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;
});
}
}
W mojej służbie
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});
}
}
Oto demo na Stackblitz