부모 구성 요소 ( 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 +에서 하위 구성 요소의 입력이 변경 될 때이를 감지하고 작동하는 두 가지 방법이 있습니다.
- 이전 답변에서 언급 한 것처럼 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 예 : 이 플런저를보십시오
- 또는 다음과 같이 입력 특성 설정기를 사용할 수도 있습니다 .
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) 이면 상위 구성 요소가 하위 컴포넌트로 전달하는 데이터를 변경할 때마다 실행됩니다 . 그러나 다음 시나리오에서는 실행되지 않으며 작동하려면 추가 조치를 취해야합니다.
-
JS 프리미티브 데이터 유형 대신 중첩 객체 또는 배열을 사용하여 부모에서 자식으로 데이터를 전달하는 경우 사용자의 답변에서 언급했듯이 변경 감지 (setter 또는 ngchanges 사용)가 발생하지 않을 수 있습니다 (muetzerich). 해결책은 여기를 참조하십시오 .
-
각도 컨텍스트 외부에서 데이터를 변경하는 경우 (즉, 외부에서) 각도는 변경 사항을 알 수 없습니다. 외부 변경을 각도로 인식하여 변경 감지를 트리거하려면 구성 요소에서 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
});
}