[angular] @Input () 값이 Angular에서 언제 변경되는지 감지하는 방법은 무엇입니까?

부모 구성 요소 ( CategoryComponent ), 자식 구성 요소 ( videoListComponent ) 및 ApiService가 있습니다.

나는이 작업을 대부분 잘 수행하고 있습니다. 즉, 각 구성 요소가 json API에 액세스하고 관찰 가능 항목을 통해 관련 데이터를 얻을 수 있습니다.

현재 비디오 목록 구성 요소는 모든 비디오를 가져옵니다.이를 특정 카테고리의 비디오로만 필터링하고 싶습니다 @Input().

CategoryComponent.html

<video-list *ngIf="category" [categoryId]="category.id"></video-list>

이것은 작동하며 부모 CategoryComponent 범주가 변경되면 categoryId 값이 전달 @Input()되지만 VideoListComponent에서이를 감지하고 APIService를 통해 비디오 배열을 다시 요청해야합니다 (새 categoryId 포함).

AngularJS $watch에서 변수에 대해 수행했을 것 입니다. 이것을 처리하는 가장 좋은 방법은 무엇입니까?



답변

실제로 angular2 +에서 하위 구성 요소의 입력이 변경 될 때이를 감지하고 작동하는 두 가지 방법이 있습니다.

  1. 이전 답변에서 언급 한 것처럼 ngOnChanges () 수명주기 메소드 를 사용할 수 있습니다 .
    @Input() categoryId: string;

    ngOnChanges(changes: SimpleChanges) {

        this.doSomething(changes.categoryId.currentValue);
        // You can also use categoryId.previousValue and 
        // categoryId.firstChange for comparing old and new values

    }

문서 링크 : ngOnChanges, SimpleChanges, SimpleChange
Demo 예 : 이 플런저를보십시오

  1. 또는 다음과 같이 입력 특성 설정기를 사용할 수도 있습니다 .
    private _categoryId: string;

    @Input() set categoryId(value: string) {

       this._categoryId = value;
       this.doSomething(this._categoryId);

    }

    get categoryId(): string {

        return this._categoryId;

    }

설명서 링크 : 여기를 참조하십시오 .

데모 예 : 이 플 런커를보십시오 .

어떤 접근법을 사용해야합니까?

컴포넌트에 여러 개의 입력이있는 경우 ngOnChanges ()를 사용하면 ngOnChanges () 내에서 모든 입력에 대한 모든 변경 사항을 한 번에 가져옵니다. 이 방법을 사용하면 변경된 입력의 현재 값과 이전 값을 비교하고 그에 따라 조치를 취할 수 있습니다.

그러나 특정 단일 입력 만 변경하고 다른 입력에 신경 쓰지 않을 때 무언가를 수행하려는 경우 입력 속성 설정기를 사용하는 것이 더 간단 할 수 있습니다. 그러나이 방법은 변경된 입력의 이전 값과 현재 값을 비교할 수있는 기본 방법을 제공하지 않습니다 (ngOnChanges 수명주기 방법으로 쉽게 수행 할 수 있음).

2017-07-25 편집 : 각도 변경 감지로 인해 일부 상황에서 여전히 화재가 발생하지 않을 수 있음

일반적으로 setter 및 ngOnChanges 모두에 대한 변경 감지 는 데이터가 JS 기본 데이터 유형 (string, number, boolean) 이면 상위 구성 요소가 하위 컴포넌트로 전달하는 데이터를 변경할 때마다 실행됩니다 . 그러나 다음 시나리오에서는 실행되지 않으며 작동하려면 추가 조치를 취해야합니다.

  1. JS 프리미티브 데이터 유형 대신 중첩 객체 또는 배열을 사용하여 부모에서 자식으로 데이터를 전달하는 경우 사용자의 답변에서 언급했듯이 변경 감지 (setter 또는 ngchanges 사용)가 발생하지 않을 수 있습니다 (muetzerich). 해결책은 여기를 참조하십시오 .

  2. 각도 컨텍스트 외부에서 데이터를 변경하는 경우 (즉, 외부에서) 각도는 변경 사항을 알 수 없습니다. 외부 변경을 각도로 인식하여 변경 감지를 트리거하려면 구성 요소에서 ChangeDetectorRef 또는 NgZone을 사용해야 할 수도 있습니다. 이것을 참조하십시오 .


답변

ngOnChanges()컴포넌트에서 라이프 사이클 방법을 사용하십시오 .

ngOnChanges는 데이터 바인딩 된 속성을 확인한 직후와 뷰 및 내용 자식 중 하나 이상이 변경되었는지 확인하기 전에 호출됩니다.

다음은 문서 입니다.


답변

SimpleChanges함수 서명에서 유형을 사용할 때 콘솔과 컴파일러 및 IDE에서 오류가 발생했습니다 . 오류를 방지하려면 any대신 서명 에서 키워드를 사용하십시오 .

ngOnChanges(changes: any) {
    console.log(changes.myInput.currentValue);
}

편집하다:

Jon이 아래에 지적했듯이 점 SimpleChanges표기법 대신 대괄호 표기법을 사용할 때 서명을 사용할 수 있습니다 .

ngOnChanges(changes: SimpleChanges) {
    console.log(changes['myInput'].currentValue);
}


답변

가장 안전한 방법은 매개 변수 대신 공유 서비스를 사용 하는 입니다 @Input. 또한 @Input매개 변수는 복잡한 중첩 개체 유형의 변경 사항을 감지하지 않습니다.

간단한 서비스 예는 다음과 같습니다.

Service.ts

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class SyncService {

    private thread_id = new Subject<number>();
    thread_id$ = this.thread_id.asObservable();

    set_thread_id(thread_id: number) {
        this.thread_id.next(thread_id);
    }

}

Component.ts

export class ConsumerComponent implements OnInit {

  constructor(
    public sync: SyncService
  ) {
     this.sync.thread_id$.subscribe(thread_id => {
          **Process Value Updates Here**
      }
    }

  selectChat(thread_id: number) {  <--- How to update values
    this.sync.set_thread_id(thread_id);
  }
}

다른 구성 요소에서 유사한 구현을 사용할 수 있으며 모든 구성 요소가 동일한 공유 값을 공유합니다.


답변

값이 기본 값이 아닌 DoCheck경우 유용한 다른 수명주기 후크가 있음을 추가하고 싶습니다 @Input.

배열 Input이 있으므로 OnChanges내용이 변경 될 때 이벤트가 발생하지 않습니다 (앵귤러가 ‘간단하고’깊지 않기 때문에 배열의 내용이 변경되었지만 배열이 여전히 배열이기 때문에).

그런 다음 변경된 배열로 뷰를 업데이트할지 여부를 결정하기 위해 사용자 정의 검사 코드를 구현합니다.


답변

  @Input()
  public set categoryId(categoryId: number) {
      console.log(categoryId)
  }

이 방법을 사용해보십시오. 도움이 되었기를 바랍니다


답변

부모 구성 요소 (CategoryComponent)의 변경 사항을 트리거하고 자식 구성 요소의 구독에서 수행 할 작업을 수행하는 관찰 가능 항목을 가질 수도 있습니다. (videoListComponent)

service.ts
public categoryChange$ : ReplaySubject<any> = new ReplaySubject(1);

-----------------
CategoryComponent.ts
public onCategoryChange(): void {
  service.categoryChange$.next();
}

-----------------
videoListComponent.ts
public ngOnInit(): void {
  service.categoryChange$.subscribe(() => {
   // do your logic
});
}