Angular는 AngularJS $ watch와 동일합니까?


213

AngularJS에서는의 $watch기능을 사용하여 범위 변수의 변화를 관찰 할 감시자를 지정할 수있었습니다 $scope. Angular에서 변수 변경 (예 : 구성 요소 변수)을 관찰하는 것과 동등한 것은 무엇입니까?


typescript에서 get 접근자를 사용하십시오.
jmvtrinidad

이 문서 확인 의 차이를 설명
최대 Koretskyi

답변:


268

Angular 2에서 변경 감지는 자동으로 수행 $scope.$watch()되며 $scope.$digest()RIP

불행하게도, 개발 가이드의 변경 감지 섹션은 아직 작성되지 않았습니다 ( 아키텍처 개요 페이지 하단 근처의 "기타 항목"에 자리 표시자가 있음).

변경 감지 작동 방식에 대한 이해는 다음과 같습니다.

  • Zone.js "원숭이가 세상을 패치한다"-브라우저에서 모든 비동기 API를 가로 챈다 (Angular가 실행될 때). 이것이 원숭이 패치 이기 때문에 setTimeout()우리가 구성 요소 내부에서 사용할 수있는 이유 입니다.$timeoutsetTimeout()
  • Angular는 "변경 감지기"트리를 구축하고 유지합니다. 구성 요소 / 지시문마다 이러한 변경 감지기 (클래스)가 있습니다. 을 주입하여이 객체에 액세스 할 수 있습니다 ChangeDetectorRef. 이러한 변경 감지기는 Angular가 구성 요소를 만들 때 만들어집니다. 더티 검사를 위해 모든 바인딩 상태를 추적합니다. 이것은 $watches()Angular 1이 {{}}템플릿 바인딩 을 위해 설정 한 것과 자동으로 비슷합니다 .
    Angular 1과 달리 변경 감지 그래프는 방향이 지정된 트리이며주기를 가질 수 없습니다 (아래에서 볼 수 있듯이 Angular 2의 성능이 훨씬 향상됩니다).
  • 이벤트가 발생하면 (앵귤러 영역 내에서) 우리가 작성한 코드 (이벤트 핸들러 콜백)가 실행됩니다. 공유 응용 프로그램 모델 / 상태 및 / 또는 구성 요소의보기 상태 등 원하는 데이터를 업데이트 할 수 있습니다.
  • 그 후 Zone.js가 추가 된 후크 때문에 Angular의 변경 감지 알고리즘을 실행합니다. 기본적으로 (즉, onPush구성 요소 중 하나 에서 변경 감지 전략을 사용하지 않는 경우 ) 트리의 모든 구성 요소는 맨 처음부터 깊이 우선 순서대로 한 번 (TTL = 1) 검사됩니다. (개발 모드 인 경우 변경 감지가 두 번 실행됩니다 (TTL = 2). 이에 대한 자세한 내용은 ApplicationRef.tick () 를 참조하십시오 .) 변경 감지 오브젝트를 사용하여 모든 바인딩에 대해 더티 검사를 수행합니다.
    • 수명주기 후크는 변경 감지의 일부로 호출됩니다.
      보고자하는 구성 요소 데이터가 기본 입력 특성 (문자열, 부울, 숫자) ngOnChanges()인 경우 변경 사항을 통지하도록 구현할 수 있습니다.
      입력 속성이 참조 유형 (객체, 배열 등)이지만 참조가 변경되지 않은 경우 (예 : 기존 배열에 항목을 추가 한 경우) 구현해야합니다 ngDoCheck()(자세한 내용은 이 SO 답변 참조). 이에).
      단일 트리 워크 구현 (단방향 데이터 흐름) 때문에 구성 요소의 속성 및 / 또는 하위 구성 요소의 속성 만 변경해야합니다. 여기에 위배 되는 플런저 가 있습니다. 상태 보존 형 파이프도 할 수 당신을 여행 여기.
  • 발견 된 바인딩 변경 사항에 대해 구성 요소가 업데이트 된 후 DOM이 업데이트됩니다. 변경 감지가 완료되었습니다.
  • 브라우저는 DOM 변경 사항을 확인하고 화면을 업데이트합니다.

자세한 내용은 다음을 참조하십시오.


변수가 변경 될 때 window.addEventListener ()는 감지를 트리거하지 않습니다 ... 그것은 나를 미치게합니다. 아무것도 어디에도 없습니다.
Albert James Teddy

@AlbertJamesTeddy hostDirectiveMetadata API 문서 의 "호스트 리스너"문서를 참조하십시오 . Angular 영역 내에서 글로벌 이벤트를 듣는 방법을 설명합니다 (따라서 변경 감지가 원하는대로 트리거됩니다). 이 답변 에는 작동하는 플런 커가 있습니다.
Mark Rajcok

링크는 도움이 ... 될 것이다
리팩토링

@MarkRajcok, 변경 감지에 대한 기사를 자유롭게 추가 할 수있었습니다. 당신이 상관하지 않기를 바랍니다. 후드 아래에서 일어나는 일에 대해 자세히 설명합니다.
Max Koretskyi

단방향 데이터 흐름 규칙을 위반하는 plunkr와 관련하여 enableProdMode ()로 plunkr를 실행하면 변경 감지기가 한 번만 실행되므로 부모보기에서 업데이트가 표시되지 않습니다.
Mister_L

93

이 동작은 이제 구성 요소 수명주기의 일부입니다.

구성 요소는 OnChanges 인터페이스 에서 ngOnChanges 메서드를 구현하여 입력 변경에 액세스 할 수 있습니다.

예:

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
이것은 @Input ()에만 해당됩니다. 구성 요소 자체 데이터의 변경 사항을 추적하려는 경우 작동하지 않습니다.
LanderV

4
간단한 변수를 변경할 수 없습니다 (예 : 부울). 개체 변경 만 감지됩니다.
mtoloo

왜 컴포넌트의 데코레이터에 "입력"배열을 추가해야합니까? 변경 감지는 이것 없이도 작동합니다.
길 Epshtain

68

자동 양방향 바인딩 외에도 값이 변경 될 때 함수를 호출하려는 경우 양방향 바인딩 바로 가기 구문을보다 자세한 버전으로 분리 할 수 ​​있습니다.

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

속기

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

(예 : http://victorsavkin.com/post/119943127151/angular-2-template-syntax 참조 )

다음과 같이 할 수 있습니다.

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


마지막 예제에서 ngModel 주위에 []를 제거 하시겠습니까?
Eugene Kulabuhov

16

각도 2에서 시계를 사용 getter function하거나 get accessor시계 역할을 할 수 있습니다 .

여기 데모를 참조 하십시오 .

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

다음은 모델에 getter 및 setter 함수를 사용하는 다른 방법입니다.

@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
이 주제는 미쳤다. 복잡한 양식에 묶인 많은 속성을 가진 객체가 있습니다. 나는 (change)그들 각각에 핸들러 를 추가하고 싶지 않다 . get|sets내 모델의 모든 속성에 s 를 추가하고 싶지 않습니다 . 그것은을 추가하는 데 도움이되지 않습니다 get|set에 대한 this.object; ngOnChanges() 단지 변경 감지 @Input . 이런 만나요! 그들은 우리에게 무엇을 했습니까 ??? 우리에게 어떤 종류의 깊은 시계를 돌려주십시오!
Cody

6

양방향 바인딩으로 만들려면을 사용할 수 [(yourVar)]있지만 yourVarChange변수를 변경할 때마다 이벤트 를 구현 하고 호출해야합니다.

영웅 변화를 추적하기 위해 이와 같은 것

@Output() heroChange = new EventEmitter();

영웅이 바뀌면 전화 해 this.heroChange.emit(this.hero);

[(hero)]당신을위한 나머지를 할 것 바인딩

여기 예를보십시오 :

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



2

이것은 질문에 직접 대답하지는 않지만 angularJs에서 $ watch를 사용할 무언가를 해결하기 위해이 스택 오버플로 질문에 착수했습니다. 나는 현재 답변에 설명 된 것과 다른 접근법을 사용하여 누군가가 유용하다고 생각하는 경우 공유하고 싶습니다.

나는 비슷한 달성하기 위해 사용하는 기술은 $watch사용하는 것입니다 BehaviorSubject( 여기에 주제에 대한 더 많은 각도 서비스), 내 구성 요소가 변경 (시계)를 얻기 위해 여기에 가입 할 수 있습니다. 이것은 $watch앵귤러 J 와 비슷 하지만 더 많은 설정과 이해가 필요합니다.

내 구성 요소에서 :

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;
    });
  }
}

내 서비스에서

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});
  }
}

다음은 Stackblitz 의 데모입니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.