FE/Angular

[Angular] @ViewChild 알아보기

monkeykim 2024. 11. 8. 00:11

Angular에서 컴포넌트 간의 데이터와 메소드를 공유하는 방법은 여러가지가 있지만, 부모 컴포넌트가 자식 컴포넌트를 제어해야 하는 상황에서는 @ViewChild 데코레이터가 가장 효율적입니다. @ViewChild를 사용하면 부모 컴포넌트가 자식 컴포넌트의 특정 속성, 메소드, 또는 DOM 요소에 접근할 수 있어 다양한 상황에서 유용하게 활용됩니다.


@ViewChild란?

@ViewChild는 자식 컴포넌트나 특정 DOM요소에 대한 참조를 가져와 부모 컴포넌트에서 해당 요소를 직접 제어할 수 있도록 해주는 Angular의 데코레이터입니다. 템플릿에서 자식 컴포넌트나 HTML 요소를 찾고, JS에서 이를 참조하여 다양한 작업을 수행할 수 있습니다.

공식문서 ViewChild: https://angular.dev/api/core/ViewChild

 

Angular

The web development framework for building modern apps.

angular.dev


@ViewChild 기본 사용법

예시: 자식 컴포넌트의 메소드 호출

1. 자식 컴포넌트 생성

자식 컴포넌트에서 sayHello 메소드를 정의하고 이 메소드는 나중에 부모 컴포넌트에서 호출합니다.

// child.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `<p>안녕하세요, 저는 자식 컴포넌트입니다.</p>`
})
export class ChildComponent {
  sayHello() {
    console.log('안녕하세요! 자식 컴포넌트입니다.');
  }
}

 

2. 부모 컴포넌트에서 @ViewChild로 자식 컴포넌트 제어

부모 컴포넌트에서 자식 컴포넌트의 sayHello 메소드를 호출하기 위해 @ViewChild를 사용하여 자식 컴포넌트의 인스턴스를 가져옵니다.

// parent.component.ts
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
  selector: 'app-parent',
  template: `
    <app-child></app-child>
    <button (click)="callChildMethod()">자식 메서드 호출</button>
  `
})
export class ParentComponent implements AfterViewInit {
  @ViewChild(ChildComponent) childComponent!: ChildComponent;

  ngAfterViewInit() {
    // 컴포넌트가 완전히 초기화된 후, ViewChild로 접근할 수 있습니다.
    this.childComponent.sayHello(); // 콘솔에 "안녕하세요! 자식 컴포넌트입니다." 출력
  }

  callChildMethod() {
    this.childComponent.sayHello(); // 버튼 클릭 시 메서드 호출
  }
}

여기에서는 버튼 클릭 시, callChildMethod 메소드가 호출되어 자식 컴포넌트의 sayHello 메소드가 실행됩니다. 이처럼 @ViewChild를 통해 자식 컴포넌트의 메소드를 부모 컴포넌트에서 호출할 수 있습니다.


@ViewChild의 옵션

@ViewChild는 2가지의 옵션을 지원합니다.

  1. 첫 번째 매개변수: 선택자
    • 자식 컴포넌트 타입, css 셀렉터, 템플릿 참조 변수 등을 사용할 수 있습니다.
  2. 두 번째 매개변수: { static: true | false }
    • static: true: 템플릿 구조가 변하지 않고, 컴포넌트가 초기화될 때, 참조가 필요할 때 사용합니다.
    • static: false: 동적으로 추가되는 요소에 사용할 수 있으며, ngAfterViewInit 이후에 참조를 설정합니다.

@ViewChild 활용

1. HTML 요소에 @ViewChild 적용하기

HTML 요소에 직접 접근하고, 스타일을 동적으로 변경하는 예제입니다.

// parent.component.ts
import { Component, ViewChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-parent',
  template: `
    <div #myDiv>이것은 Div 요소입니다.</div>
    <button (click)="changeDivStyle()">스타일 변경</button>
  `
})
export class ParentComponent {
  @ViewChild('myDiv') myDiv!: ElementRef;

  changeDivStyle() {
    this.myDiv.nativeElement.style.backgroundColor = 'lightblue';
  }
}

여기에서 @ViewChild를 통해 #myDiv 로 지정된 div요소에 접근하고, changeDivStyle 메소드에서 해당 요소의 배경색을 동적으로 변경합니다.

 

2. 조건에 따라 동적 참조 설정하기

옵션을 이용하여 조건에 따라 @ViewChild를 설정할 수 있습니다.

// parent.component.ts
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
  selector: 'app-parent',
  template: `
    <app-child *ngIf="isChildVisible"></app-child>
    <button (click)="toggleChild()">자식 컴포넌트 표시/숨기기</button>
  `
})
export class ParentComponent implements AfterViewInit {
  @ViewChild(ChildComponent, { static: false }) childComponent!: ChildComponent;
  isChildVisible = true;

  ngAfterViewInit() {
    if (this.childComponent) {
      this.childComponent.sayHello();
    }
  }

  toggleChild() {
    this.isChildVisible = !this.isChildVisible;
  }
}

여기에서는 isChildVisible 값에 따라 app-child 컴포넌트를 동적으로 표시하거나 숨깁니다. 또한 @ViewChild를 선언할 때 static: false로 설정하였기 때문에 ngAfterViewInit 이후에만 @ViewChild로 접근이 가능합니다.


@ViewChild 주의 사항

  • 초기화 순서: @ViewChild는 Angular의 뷰 초기화 주기와 관련이 있습니다. 따라서 ngOnInit 에서는 사용하지 않고, ngAfterViewInit 에서 참조하는 것이 좋습니다.
  • 동적 요소에 대한 접근: static: false로 설정하면 동적으로 생성되는 요소에 대해 @ViewChild를 사용할 수 있습니다. 템플릿 구조가 변경될 가능성이 있는 경우라면 유용합니다.
  • DOM 직접 조작 주의: Angular는 주로 데이터 바인딩 방식을 사용하므로, @ViewChild로 직접 DOM을 조작하는 경우 성능에 영향을 줄 수 있습니다. 따라서 직접 DOM을 다뤄야 하는 경우에만 사용하고, 가능한 한 Angular의 데이터 바인딩과 반응형 프로그래밍을 우선으로 고려해야 합니다.