내용으로 건너뛰기
ViewChild와 ContentChild는 Angular에서 무엇인가요?

ViewChild와 ContentChild는 Angular에서 무엇인가요?

이 블로그는 ViewChild 및 ContentChild Angular 컴포넌트의 뷰 내에서 자식 컴포넌트 및 DOM 요소에 액세스하고 조작할 수 있는 방법을 보여줍니다. 모두 읽어보세요.

7분 읽기

Angular의 ViewChild와 ContentChild는 컴포넌트 통신에 사용됩니다. 예를 들어, 부모 Angular 컴포넌 트가 자식 컴포넌트에 접근하고 싶을 때는 ViewChild 또는 ContentChild를 사용합니다.

그렇다면 이번 블로그 글에서는 Angular ViewChild와 Angular ContentChild의 본질을 설명하고, 여러분의 앱에서 어떻게 활용하는지 보여드리겠습니다.

ViewChild가 Angular에서 무엇인가

Angular ViewChild또는ViewChildren데코레이터는구성 요소 참조 이름이나 클래스 이름을사용해 템플릿에 쿼리하여 구성 요소 인스턴스에 대한 참조를 얻는 데 사용됩니다. Angular의 ViewChild첫 번째 매칭컴포넌를 반환하고,ViewChildren은모든 매칭 컴포넌트를QueryList 항목으로 반환 합니다. 이 참조를 사용해컴포넌트클래스나 DOM 요소를 다룰 수 있습니다. 

부모 컴포넌트 내에서 다음 항목에 접근하고 싶다면, Angular의 데코레이터@ViewChild 사용하세요.

Using MessageComponent

아래 목록과 같이 MessageComponent가 있다고 가정해 봅시다:

import { Component, Input } from "@angular/core";
@Component({
    selector: "app-message",
    template: `<h2>{{message}}</h2>`,
})
export class MessageComponent {
    @Input() message: string;
}

여기 보이는 대로 AppComponent 안에 MessageComponent를 사용하고 있습니다:

import { Component, OnInit } from "@angular/core";
@Component({
    selector: "app-root",
    template: ` <div>
        <h1>Messages</h1>
        <app-message [message]="message"></app-message>
    </div>`,
})
export class AppComponent implements OnInit {
    message: any;
    ngOnInit() {
        this.message = "Hello World !";
    }
}

MessageComponent는 AppComponent의 템플릿 내에 위치하게 됩니다. 따라서 ViewChild로 접근할 수 있습니다.

export class AppComponent implements OnInit, AfterViewInit {
    message: any;
    @ViewChild(MessageComponent) messageComponent: MessageComponent;

    ngAfterViewInit() {
        console.log(this.messageComponent);
    }

    ngOnInit() {
        this.message = "Hello World !";
    }
}

MessageComponent의 값 변경

이제 MessageComponent 속성의 값을 변경해 보겠습니다.

ngAfterViewInit() {
   console.log(this.messageComponent);
   this.messageComponent.message = 'Passed as View Child';
}

여기서는 ViewChild 속성의 값을 변경하고 있습니다.

Angular ViewChildren과 QueryList 작업

우리는 *ngFor 지시문 안에 MessageComponent를 사용하고 있습니다; 따라서 MessageComponent에 대한 참조가 여러 번 존재합니다. 현재 ViewChildren과 QueryList로 접근할 수 있으며, 아래 목록에서 확인할 수 있습니다:

@ViewChildren(MessageComponent) messageComponent: QueryList<MessageComponent>;
   ngAfterViewInit() {
    console.log(this.messageComponent);
   }

출력물에서는 MessageComponent에 대한 다양한 참조가 ViewChildern으로 나타납니다.

이제 아래 목록에 보이는 ViewChildren의 속성을 업데이트해 보겠습니다:

ngAfterViewInit() {
   console.log(this.messageComponent);
   this.messageComponent.forEach((item) => { item.message = 'Infragistics'; });
}

보시다시피, 저희는 Angular ViewChildren의 각 항목을 반복 검토하며 각 속성을 업데이트하고 있습니다. 이 경우 속성 값이 업데이트되지만, 역시 "마지막 확인 후 표현식이 변경되었습니다." 라는 오류가 발생합니다.

ViewChild 같은 변경 감지를 수동으로 호출하면 해결할 수 있습니다. AfterContentInit 라이프사이클 훅에는 ViewChildren 참조가 없다는 점을 유념하세요. 아래 목록에 나와 같이 ngAfterContentInit() 생명주기 훅에서 ViewChildren 참조를 위한 undefine(불정의)이 나타납니다:

ngAfterContentInit() {
   console.log(this.messageComponent); // undefined 
}

하지만 수동으로 변경 감지를 호출해 "마지막 확인 후 표현식이 변경되었습니다" 라는 오류를 수정할 수 있습니다.

 변화 감지 메커니즘을 사용하는 것

  1. @angular/core에서 ChangeDetectorRef를 가져오기
  2. Component 클래스의 생성자에 주입하세요
  3. ViewChild 속성이 변경된 후 detectChanges() 메서드를 호출합니다

아래 목록과 같이 수동 변경 감지 기능을 사용할 수 있습니다:

@ViewChildren(MessageComponent) messageComponent: QueryList<MessageComponent>;
	constructor(private cdr: ChangeDetectorRef) {
}
ngAfterViewInit() {
	console.log(this.messageComponent);
	this.messageComponent.forEach((item) => { item.message = 'Infragistics'; });
	this.cdr.detectChanges();
}

ContentChild가 Angular에서 무엇인가요?

Angular ContentChild 속성 장식기는 ViewChild와 매우 유사하며, 컴포넌트 내에서 투영된 콘텐츠와 상호작용하고 조작하는 강력한 방식을 제공합니다. 이를 사용하면 DOM에서 Projected Content에 대한 참조를 쉽게 얻을 수 있습니다.

먼저 ContentChild에 대해 이해하는 것부터 시작해 봅시다. 템플릿 내에 위치한 모든 요소는 ContentChild입니다.

이해하기 위해 MessageContainerComponent를 살펴보겠습니다.

import { Component } from "@angular/core";
@Component({
    selector: "app-messagecontainer",
    template: ` <div>
        <h3>{{greetMessage}}</h3>
        <ng-content select="app-message"></ng-content>
    </div>`,
})
export class MessageContainerComponent {
    greetMessage = "Ignite UI Rocks!";
}

이 구성 요소에서는 Angular 콘텐츠 투사를 사용하고 있습니다.

ContentChild에서 MessageComponent Angular 전달하기

<-content> 내에 투사된 모든 요소나 컴포넌트는 ContentChild가 됩니다. MessageContainerComponent 내에 투영된 MessageComponent에 접근하고 통신하고 싶다면, ContentChild로 읽어야 합니다.

Angular에서 ContentChild를 배우기 전에, 먼저 MessageContainerComponent가 어떻게 사용되고 MessageComponent가 어떻게 프로젝션되는지 확인해 보세요.

import { Component, OnInit } from "@angular/core";
@Component({
    selector: "app-root",
    template: ` <div>
        <app-messagecontainer>
            <app-message [message]="message"></app-message>
        </app-messagecontainer>
    </div>`,
})
export class AppComponent implements OnInit {
    message: any;
    ngOnInit() {
        this.message = "Hello World !";
    }
}

위 목록에서 보시다시피, 우리는 AppComponent에서 MessageContainerComponent를 사용하고, 그 안에 MessageComponent를 투영하도록 전달합니다. MessageComponent는 콘텐츠 투영과 함께 MessageContainerComponent에 사용되므로 ContentChild Angular 됩니다.

MessageComponnet은 MessageContainerComponent 템플릿 내에서 프로젝션되어 사용되기 때문에, 아래에 보이는 것처럼 ContentChild로 사용할 수 있습니다:

import { Component, ContentChild, AfterContentInit } from "@angular/core";
import { MessageComponent } from "./message.component";

@Component({
    selector: "app-messagecontainer",
    template: ` <div>
        <h3>{{greetMessage}}</h3>
        <ng-content select="app-message"></ng-content>
    </div>`,
})
export class MessageContainerComponent implements AfterContentInit {
    greetMessage = "Ignite UI Rocks!";
    @ContentChild(MessageComponent) MessageComponentContentChild: MessageComponent;
    ngAfterContentInit() {
        console.log(this.MessageComponentContentChild);
    }
}

우리는 다음과 같은 작업을 해야 합니다:

  1. @angular/core에서 ContentChild와 AfterContentInit을 가져오세요.
  2. 컴포넌트 클래스에 AfterContentInit 라이프사이클 훅을 구현하세요.
  3. 데코레이터 @ContentChild로 부동산을 만드세요.
  4. ngAfterContentInit 생애 주기 훅 안에 그 부분을 접근하세요.

컴포넌트의 ngAfterContentInit 라이프사이클 훅 내에서 ContentChild 속성을 수정할 수 있습니다. 아래 목록에서 보듯이 두 개 이상의 MessageComponent가 투영되어 있다고 가정해 봅시다:

import { Component, OnInit } from "@angular/core";
@Component({
    selector: "app-root",
    template: ` <div>
        <app-messagecontainer>
            <app-message *ngFor="let m of messages" [message]="m"></app-message>
        </app-messagecontainer>
    </div>`,
})
export class AppComponent implements OnInit {
    messages: any;
    ngOnInit() {
        this.messages = this.getMessage();
    }
    getMessage() {
        return ["Hello India", "Which team is winning Super Bowl? ", "Have you checked Ignite UI ?", "Take your broken heart and make it to the art"];
    }
}

이제 우리는 ContentChild가 하나 이상 있으므로, 아래 목록과 같이 ContentChildren으로 접근해야 합니다:

export class MessageContainerComponent implements AfterContentInit {
    greetMessage = "Ignite UI Rocks!";
    @ContentChildren(MessageComponent) MessageComponentContentChild: QueryList<MessageComponent>;
    ngAfterContentInit() {
        console.log(this.MessageComponentContentChild);
    }
}

ContentChildren과 QueryList 작업

ContentChildren과 QueryList를 사용하려면 다음 작업을 수행해야 합니다:

  1. @angular/core에서 ContentChildren, QueryList, AfterContentInit 를 가져오세요.
  2. QueryList 타입의 데코레이터 @ContentChildren으로 속성을 생성하세요.
  3. ngAfterContentInit() 라이프사이클 훅에서 ContentChildren 참조에 접근하세요.

ContentChildren에서 각 항목을 쿼리하고 다음과 같이 속성을 수정할 수 있습니다:

ngAfterContentInit() {
   this.MessageComponentContentChild.forEach((m) => m.message = 'Foo');
}

이것이 바로 ContentChildren과 함께 작업할 수 있는 방법 Angular 것입니다.

싸다

ViewChild와 ContentChild는 Angular의 매우 중요한 두 가지 기능입니다. 이들은 부모 컴포넌트의 자식 컴포넌트에 접근할 수 있도록 하는 데 사용됩니다. 구성 요소 템플릿에 포함된 모든 지시, 컴포넌트, 요소는 ViewChild로 접근됩니다. 반면, <ng-content> 내에 투영된 모든 요소나 컴포넌트는 ContentChild로 접근됩니다.

Angular ViewChild와 ContentChild를 더욱 단순화하고 싶다면, 저희의 완전한 기능을 갖춘 Ignite UI for Angular 구성 요소 라이브러리를 사용해 보세요. 가장 빠른 Angular 데이터 그리드와 60+ 고성능 차트를 제공하여 현대적이고 고성능 Angular 앱을 쉽게 구축할 수 있도록 지원합니다.

(Last Updated: 08.09.2023)

Ignite UI for Angular

데모 요청