심화 가이드
컴포넌트

입력 프로퍼티로 데이터 받기

팁: 이 가이드 문서는 핵심 가이드 이후 내용을 다룹니다. 아직 Angular에 익숙하지 않다면 해당 문서를 먼저 읽어보세요.

팁: 만약 웹 프레임워크에 익숙하다면, 입력 프로퍼티는 프롭스(pros) 와 비슷하다고 이해해도 됩니다.

컴포넌트를 사용하다 보면 컴포넌트에 데이터를 전달하는 경우가 자주 있습니다. 이 경우 컴포넌트의 입력 프로퍼티 를 활용하면 됩니다:

      
import {Component, input} from '@angular/core';@Component({/*...*/})export class CustomSlider {// `value` 라는 이름으로 입력 프로퍼티를 선언하고 기본값 0을 할당합니다.value = input(0);}

그러면 템플릿에서 이렇게 프로퍼티 바인딩 할 수 있습니다:

      
<custom-slider [value]="50" />

입력 프로퍼티에 기본값이 있으면 TypeScript는 기본값을 기준으로 타입을 추론합니다:

      
@Component({/*...*/})export class CustomSlider {  // TypeScript는 숫자를 입력받는 것을 기준으로 InputSignal<number> 타입으로 추론합니다.  value = input(0);}

입력 프로퍼티에 제네릭 함수를 사용하는 경우에는 타입을 명확하게 지정할 수도 있습니다.

입력 프로퍼티에 기본값을 할당하지 않으면 undefined로 추론됩니다.

      
@Component({/*...*/})export class CustomSlider {  // 입력 프로퍼티 `value`의 기본값이 할당되지 않았기 때문에 타입은 InputSignal<number | undefined> 으로 추론됩니다.  value = input<number>();}

Angular는 입력 프로퍼티를 컴파일 시점에 정적으로 분석합니다. 그래서 실행 시점에 입력 프로퍼티를 추가하거나 제거할 수 없습니다.

그리고 input 함수는 Angular 컴파일러 관점에서 특별한 의미를 갖습니다. input 함수는 컴포넌트 프로퍼티나 디렉티브 프로퍼티를 초기화할 때만 사용할 수 있습니다.

컴포넌트 클래스를 상속받는 경우, 자식 클래스는 부모 클래스의 입력 프로퍼티를 상속받습니다.

입력 프로퍼티는 대소문자를 구분합니다.

입력 프로퍼티 값 읽기

input 함수는 InputSignal을 반환합니다. 이 시그널의 값을 읽으려면 시그널을 실행하면 됩니다:

      
import {Component, input} from '@angular/core';@Component({/*...*/})export class CustomSlider {// `value` 라는 이름으로 입력 프로퍼티를 선언하고 기본값 0을 할당합니다.value = input(0);// `value` 입력 프로퍼티를 기반으로 연산 시그널을 생성합니다.label = computed(() => `The slider's value is ${this.value()}`);}

input 함수로 만든 시그널은 읽기 전용 시그널입니다.

필수 입력값

입력 프로퍼티 값을 필수 항목으로 지정하려면 input 함수 대신 input.required 함수를 사용하면 됩니다:

      
@Component({/*...*/})export class CustomSlider {  // `value` 라는 이름으로 입력 프로퍼티를 선언하고 `InputSignal<number>`를 할당합니다.  value = input.required<number>();}

이렇게 구현하면 템플릿에 컴포넌트가 사용될 때 입력값을 반드시 지정해야 합니다. 입력값 없이 컴포넌트를 사용하면 빌드 시점에 오류가 발생합니다.

입력 프로퍼티가 필수인 경우에는 InputSignal의 제네릭에 undefined를 추가하지 않는 한 undefined를 포함하지 않습니다.

입력 프로퍼티 설정하기

input 함수에 두번째 인자로 옵션 객체를 전달할 수 있습니다.

입력값 변환

입력 프로퍼티로 받은 값을 변환해서 할당하려면 transform 함수를 사용하면 됩니다.

      
@Component({  selector: 'custom-slider',  /*...*/})export class CustomSlider {  label = input('', {transform: trimString});}function trimString(value: string | undefined): string {return value?.trim() ?? '';}
      
<custom-slider [label]="systemVolume" />

이렇게 구현하면 systemVolume 값이 변경될 때 trimString 함수가 실행되고 그 결과값이 label에 할당됩니다.

입력값을 변환하는 경우는 null 값과 undefined 값을 포함해서 템플릿에 사용되는 값의 타입을 완화하는 경우에 자주 사용됩니다.

입력 프로퍼티 변환 함수는 빌드 시점에 정적으로 분석됩니다. 그래서 변환 함수는 조건에 따라 결정하거나 표현식의 결과로 할당할 수는 없습니다.

입력 프로퍼티 변환 함수는 반드시 순수 함수(pure functions)여야 합니다. 변환 함수 외부 상태에 영향을 받으면, 변환 함수의 결과값을 예측할 수 없습니다.

타입 검사

입력 프로퍼티 변환 함수를 지정할 때, 변환 함수의 인자 타입에 따라 템플릿에서 입력 프로퍼티에 할당할 수 있는 타입이 결정됩니다.

      
@Component({/*...*/})export class CustomSlider {  widthPx = input('', {transform: appendPx});}function appendPx(value: number): string {return `${value}px`;}

위 코드처럼 구현하면 입력 프로퍼티 widthPxInputSignal로 문자열을 반환받더라도 number 타입을 인자로 받습니다.

기본 변환 함수

불리언 타입과 숫자 타입을 변환하는 작업은 자주 사용되기 때문에 Angular가 기본 변환 함수를 제공합니다.

      
import {Component, input, booleanAttribute, numberAttribute} from '@angular/core';@Component({/*...*/})export class CustomSlider {disabled = input(false, {transform: booleanAttribute});value = input(0, {transform: numberAttribute});}

booleanAttribute는 표준 HTML 불리언 어트리뷰트를 따라해서 어트리뷰트 값이 존재하면 "true" 값으로 변환합니다. 그리고 booleanAttribute"false" 문자열을 받으면 불리언 false 값으로 변환합니다.

numberAttribute는 값이 주어지면 숫자로 변환합니다. 숫자 파싱이 실패하면 NaN로 변환됩니다.

별칭

템플릿에 사용하는 입력 프로퍼티 이름을 다르게 사용하려면 alias 옵션을 사용하면 됩니다.

      
@Component({/*...*/})export class CustomSlider {  value = input(0, {alias: 'sliderValue'});}
      
<custom-slider [sliderValue]="50" />

이 별칭은 TypeScript 코드에서 사용하는 프로퍼티 이름에 영향을 주지 않습니다.

보통은 컴포넌트 입력 프로퍼티에 별칭을 부여하는 것은 권장하지 않지만, 이 기능은 기존 프로퍼티 이름을 유지하면서 다른 네이티브 DOM 엘리먼트 이름과 충돌하는 것을 방지하는 용도로 사용할 때는 유용합니다.

모델 입력 프로퍼티

모델 입력 프로퍼티(Model input) 는 컴포넌트가 부모 컴포넌트로 값을 전달하는 형태의 특별한 입력 프로퍼티입니다.

모델 입력 프로퍼티는 컴포넌트를 정의할 때 일반적인 입력 프로퍼티를 선언하는 것과 비슷하게 선언합니다.

모델 입력 프로퍼티와 일반 입력 프로퍼티는 컴포넌트 안쪽으로 값을 전달할 수 있습니다. 그런데 모델 입력 프로퍼티는 컴포넌트 밖으로도 값을 전달할 수 있습니다. 그래서 이 프로퍼티는 양방향으로 바인딩 할 수 있습니다.

      
@Component({ /* ... */})export class CustomSlider {  // `value`라는 이름으로 모델 입력 프로퍼티를 선언합니다.  value = model(0);  increment() {    // 모델 입력 프로퍼티 값을 변환한 후 바인딩 된 곳으로 전달합니다.     this.value.update(oldValue => oldValue + 10);  }}@Component({  /* ... */  // 양방향 바인딩을 사용한다는 것은, 슬라이더의 값이 변경되면 자동으로 `volume` 시그널로 전달된다는 것을 의미합니다.  // 이 바인딩은 시그널의 값이 아닌 시그널의 *인스턴스*를 활용합니다.  template: `<custom-slider [(value)]="volume" />`,})export class MediaControls {  // 로컬 상태를 저장하기 위해 값을 지정할 수 있는 시그널로 `volume` 프로퍼티를 선언합니다.   volume = signal(0);}

위 예제에서 CustomSlidervalue 모델 입력 프로퍼티를 통해 값을 지정할 수 있고, 이렇게 쓴 값을 MediaControlsvolume 시그널로 전달할 수 있습니다. 이 경우 valuevolume 값은 동기화되어 유지됩니다. 바인딩 문법에서 volume 시그널의 이 아니라 시그널 인스턴스라는 것에 주의하세요.

다른 측면에서는, 모델 입력 프로퍼티는 일반적인 입력 프로퍼티와 비슷하기도 합니다. computedeffect와 연동하는 방식을 지원하며, 시그널 함수를 실행하면 값을 읽을 수 있습니다.

양방향 바인딩을 자세하게 알아보려면 양방향 바인딩 문서를 참고하세요.

일반 프로퍼티의 양방향 바인딩

일반적인 JavaScript 프로퍼티를 모델 입력 프로퍼티와 바인딩 할 수 있습니다.

      
@Component({  /* ... */  // `value` 는 모델 입력 프로퍼티입니다.  // `[()]` 문법은 양방향 바인딩을 의미합니다.  template: '<custom-slider [(value)]="volume" />',})export class MediaControls {  protected volume = 0;}

위 예제 코드에서 CustomSlidervalue 모델 입력 프로퍼티를 통해 값을 지정할 수 있습니다. 그러면 이 값은 MediaControlsvolume 프로퍼티로 다시 전달됩니다. 결국 value 프로퍼티와 volume 프로퍼티는 동기화되어 유지됩니다.

change 이벤트

컴포넌트나 디렉티브에 모델 입력 프로퍼티를 선언하면 Angular는 해당 모델에 해당하는 출력 프로퍼티를 Angular가 자동으로 생성합니다. 이 출력 프로퍼티의 이름은 입력 프로퍼티 이름에 "Change" 접미사를 붙인 것으로 결정됩니다.

      
@Directive({ /* ... */ })export class CustomCheckbox {  // "checkedChange" 출력 프로퍼티가 자동으로 생성됩니다.  // 템플릿에서 `(checkedChange)="handler()"` 라고 지정하면 출력 프로퍼티를 구독할 수 있습니다.  checked = model(false);}

이제 모델 입력 프로퍼티에 set 메서드나 update 메서드를 사용해서 값이 변경되면, Angular가 값이 변경되었다는 이벤트를 보냅니다.

출력 프로퍼티를 자세하게 알아보려면 출력 프로퍼티로 커스텀 이벤트 보내기 문서를 참고하세요.

모델 입력 프로퍼티 커스터마이징하기

모델 입력 프로퍼티는 일반 입력 프로퍼티와 같은 방식으로 필수 여부를 지정하거나 별칭을 지정할 수 있습니다.

모델 입력 프로퍼티는 변환 함수를 지원하지 않습니다.

모델 입력 프로퍼티는 언제 사용할까요

모델 입력 프로퍼티는 양방향 바인딩을 사용할 때 활용합니다. 이 방식은 일반적으로 사용자와 상호작용하면서 값을 수정해야 하는 경우에 적합합니다. 커스텀 폼 컨트롤이나 날짜 선택기, 콤보박스 같은 컨트롤에서 사용하는 것이 일반적입니다.

입력 프로퍼티 이름 정하기

HTMLElement와 같은 DOM 엘리먼트의 프로퍼티와 겹치는 이름은 사용하지 마세요. 이름이 겹치면 프로퍼티를 바인딩하는 것이 컴포넌트와 바인딩하는 것인지 DOM 엘리먼트와 바인딩하는 것인지 알 수 없습니다.

컴포넌트 셀렉터에 하듯 컴포넌트 입력 프로퍼티에 접두사를 추가하지 마세요. 엘리먼트는 컴포넌트 하나의 호스트 엘리먼트가 될 수 있기 때문에, 모든 사용자 프로퍼티는 컴포넌트에 속한 것으로 간주됩니다.

@Input 데코레이터로 입력 프로퍼티 선언하기

팁: Angular 팀은 input 함수를 사용해서 시그널 기반으로 선언하는 것을 권장합니다. 데코레이터 @Input을 사용하는 것과 기능은 같습니다.

입력 프로퍼티는 @Input 데코레이터를 사용해서 선언할 수도 있습니다:

      
@Component({...})export class CustomSlider {  @Input() value = 0;}

템플릿에서 바인딩하는 방법은 시그널을 기반으로 할 때와 같습니다:

      
<custom-slider [value]="50" />

데코레이터 기반 입력 프로퍼티를 커스터마이징하기

@Input 데코레이터는 동작방식을 지정하는 설정 객체를 인자로 받을 수 있습니다.

필수 입력 프로퍼티

required 옵션을 지정하면 입력 프로퍼티 값을 필수 항목으로 지정할 수 있습니다.

      
@Component({...})export class CustomSlider {  @Input({required: true}) value = 0;}

이제 템플릿에서 필수값을 지정하지 않고 컴포넌트를 사용하면 빌드 시점에 에러가 발생합니다.

입력값 변환

입력 프로퍼티로 들어오는 값을 변환해서 사용하고 싶다면 transform 함수를 지정하면 됩니다. 이 변환 함수는 시그널 기반에서 다뤘던 것과 동일합니다.

      
@Component({  selector: 'custom-slider',  ...})export class CustomSlider {  @Input({transform: trimString}) label = '';}function trimString(value: string | undefined) { return value?.trim() ?? ''; }

별칭

입력 프로퍼티에 별칭을 지정하려면 alias 옵션을 지정하면 됩니다.

      
@Component({...})export class CustomSlider {  @Input({alias: 'sliderValue'}) value = 0;}
      
<custom-slider [sliderValue]="50" />

@Input 데코레이터를 사용할 때 첫번째 인자를 지정하면 설정 객체 없이 별칭을 지정할 수 있습니다.

별칭은 시그널 기반에서 다뤘던 것과 동일합니다.

입력 프로퍼티의 게터(getter)와 세터(setter)

데코레이터 기반으로 입력 프로퍼티를 선언하면서 입력 프로퍼티의 게터와 세터를 추가로 구현할 수 있습니다:

      
export class CustomSlider {  @Input()  get value(): number {    return this.internalValue;  }set value(newValue: number) { this.internalValue = newValue; }private internalValue = 0; }

그리고 public 세터를 정의하면 쓰기 전용 입력 프로퍼티를 만들 수도 있습니다:

      
export class CustomSlider {  @Input()  set value(newValue: number) {    this.internalValue = newValue;  }private internalValue = 0; }

가능하다면 게터, 세터 대신 입력 프로퍼티 변환 함수를 사용하세요. Angular는 입력 프로퍼티의 세터를 여러번 실행할 수 있으며, 이 세터가 DOM을 조작하는 것처럼 성능에 영향을 많이 주는 경우에는 전체 애플리케이션 성능에 부정적인 영향을 미칠 수 있습니다.

@Component 데코레이터에서 입력 프로퍼티 정의하기

@Input 데코레이터에는 inputs 프로퍼티를 활용해서 입력 프로퍼티를 직접 지정할 수도 있습니다. 이 방식은 컴포넌트를 기본 클래스에서 상속받을 때 유용합니다:

      
// `CustomSlider`는 `BaseSlider`에서 `disabled` 프로퍼티를 상속받습니다.@Component({  ...,  inputs: ['disabled'],})export class CustomSlider extends BaseSlider { }

그리고 입력 프로퍼티를 선언할 때 콜론(:)을 사용하면 별칭을 함께 지정할 수도 있습니다:

      
// `CustomSlider`는 `BaseSlider`에서 `disabled` 프로퍼티를 상속받습니다.@Component({  ...,  inputs: ['disabled: sliderDisabled'],})export class CustomSlider extends BaseSlider { }