[Angular] 데코레이터(Decorator) 소개 및 사용방법(1)

Angular Decorator는 Angular 애플리케이션 구축의 기본 측면입니다. 이는 Angular에 처리 및 사용 방법을 알려주는 메타데이터를 제공하여 클래스, 속성, 메서드 및 매개 변수의 동작을 향상시키는 데 사용됩니다.

이 글에서는 Angular의 다양한 데코레이터 유형을 살펴보고 이를 효과적으로 사용하는 시기와 방법을 알아봅니다.

@Component

@Component 데코레이터는 Angular에서 새 컴포넌트(Component)를 정의하는 데 사용됩니다. selector, template, styles 등과 같은 컴포넌트에 대한 메타데이터를 제공하는 데 사용됩니다. 구성 개체를 매개 변수로 사용하는 클래스 데코레이터입니다.

1
2
3
4
5
@Component({
selector: 'app-my-component',
template: '<h1>Hello World!</h1>',
})
export class MyComponent {}

@Directive

@Directive 데코레이터는 Angular에서 새로운 디렉티브(Directive)을 만드는 데 사용됩니다. selector, inputs, outputs 등과 같은 지시어에 대한 메타데이터를 제공하는 데 사용됩니다. 구성 개체를 매개 변수로 사용하는 클래스 데코레이터입니다.

1
2
3
4
5
6
@Directive({
selector: '[appMyDirective]',
})
export class MyDirective {
@Input() appMyDirective: string;
}

@Injectable

@Injectable 데코레이터는 Angular에서 새로운 서비스를 정의하는 데 사용됩니다. dependencies, scope 등과 같은 서비스에 대한 메타데이터를 제공하는 데 사용됩니다. 구성 개체를 매개 변수로 사용하는 클래스 데코레이터입니다.

1
2
3
4
@Injectable({
providedIn: 'root',
})
export class MyService {}

@Pipe

@Pipe 데코레이터는 Angular에서 새 파이프를 만드는 데 사용됩니다. name, pureness 등과 같은 파이프에 대한 메타데이터를 제공하는 데 사용됩니다. 구성 개체를 매개 변수로 사용하는 클래스 데코레이터입니다.

1
2
3
4
5
6
7
8
9
@Pipe({
name: 'myPipe',
pure: true,
})
export class MyPipe implements PipeTransform {
transform(value: any): any {
return value.toUpperCase();
}
}

@Input

@Input 데코레이터는 컴포넌트나 디렉티브에서 입력 속성을 정의하는 데 사용됩니다. name, type 등 입력에 대한 메타데이터를 제공하는 데 사용됩니다. 입력 속성의 이름을 지정하는 선택적 매개 변수를 사용하는 속성 데코레이터입니다.

1
2
3
4
5
6
7
@Component({
selector: 'app-my-component',
template: '<h1>{{myInput}}</h1>',
})
export class MyComponent {
@Input() myInput: string;
}

@Output

@Output 데코레이터는 컴포넌트나 디렉티브에서 출력 속성을 정의하는 데 사용됩니다. name, type 등 출력에 대한 메타데이터를 제공하는 데 사용됩니다. 출력 속성의 이름을 지정하는 선택적 매개 변수를 사용하는 속성 데코레이터입니다.

1
2
3
4
5
6
7
8
9
10
11
@Component({
selector: 'app-my-component',
template: '<button (click)="onClick()">Click Me</button>',
})
export class MyComponent {
@Output() myOutput: EventEmitter<any> = new EventEmitter();

onClick() {
this.myOutput.emit();
}
}

@HostBinding

@HostBinding 데코레이터는 디렉티브이나 컴포넌트의 host element 속성을 디렉티브이나 컴포넌트 클래스의 속성에 바인딩하는 데 사용됩니다. 바인딩할 host 속성의 이름을 지정하는 매개변수를 받는 속성 데코레이터입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Directive({
selector: '[appHighlight]',
})
export class HighlightDirective {
@Input('appHighlight') isHighlighted: boolean;

@HostBinding('style.backgroundColor') backgroundColor: string;

constructor() {}

ngOnChanges() {
if (this.isHighlighted) {
this.backgroundColor = 'blue';
} else {
this.backgroundColor = 'transparent';
}
}
}

이 예에서 @HostBinding 데코레이터는 디렉티브의 backgroundColor 속성을 호스트 요소의 style.BackgroundColor 속성에 바인딩하는 데 사용됩니다. 이는 isHighlighted 입력이 변경되면 그에 따라 backgroundColor 속성이 업데이트된다는 의미입니다.

@HostBinding 데코레이터를 사용하여 클래스 이름과 같은 호스트 요소의 다른 속성을 바인딩할 수도 있습니다.

1
2
3
4
5
6
7
@Directive({
selector: '[appButton]',
})
export class ButtonDirective {
@HostBinding('class.btn') isButton = true;
@HostBinding('class.btn-primary') isPrimary = true;
}

이 예에서 @HostBinding 데코레이터는 isButton 속성을 호스트 요소의 btn 클래스에 바인딩하고 isPrimary 속성을 호스트 요소의 btn-primary 클래스에 바인딩하는 데 사용됩니다. 이 지시어는 모든 요소에 사용되어 부트스트랩 스타일 버튼 모양을 제공할 수 있습니다.

@HostBinding을 다른 지시어 및 서비스와 함께 사용하면 Angular 애플리케이션에서 복잡하고 동적인 UI 요소를 쉽게 생성할 수 있습니다.

@Attribute

@Attribute 데코레이터는 호스트 요소의 속성 값을 디렉티브에 삽입하는 데 사용됩니다. 이 데코레이터는 HTML 요소에서 값을 가져와 디렉티브에 사용해야 할 때 사용됩니다.

@Attribute를 사용하는 방법의 예는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Directive, Input, Attribute } from '@angular/core';

@Directive({
selector: '[myDirective]',
})
export class MyDirective {
@Input() myInput: string;
myAttribute: string;

constructor(@Attribute('my-attribute') myAttribute: string) {
this.myAttribute = myAttribute;
}
}

이 예에서 @Attribute 데코레이터는 호스트 요소의 my-attribute 속성 값을 디렉티브의 myAttribute 속성에 삽입하는 데 사용됩니다.

속성 값은 문자열로 삽입되므로 다른 형식의 값이 필요한 경우 추가 구문 분석이나 유형 변환을 수행해야 할 수도 있습니다.

@Attribute 데코레이터는 HTML 요소에서 값을 가져와 디렉티브 로직에 사용해야 할 때 유용할 수 있습니다. 그러나 이 접근 방식은 앱의 HTML 구조가 변경되면 취약한 코드로 이어질 수 있다는 점을 명심하는 것이 중요합니다.

@ContentChild

@ContentChild 데코레이터를 사용하면 컴포넌트가 해당 콘텐츠에 투영되는 디렉티브 또는 컴포넌트의 단일 인스턴스를 쿼리 할 수 있습니다.

사용

@ContentChild 데코레이터는 두 가지 방법으로 사용할 수 있습니다.

  1. 유형별로 디렉티브나 컴포넌트를 쿼리합니다.
1
2
@ContentChild(MyDirective) myDirective!: MyDirective;
@ContentChild(MyComponent) myComponent!: MyComponent;
  1. 템플릿 참조 변수로 디렉티브나 컴포넌트를 쿼리합니다.
1
<my-component #myComponentRef></my-component>
1
@ContentChild('myComponentRef', { static: true }) myComponent!: MyComponent;

Options

@ContentChild 데코레이터는 다음 속성을 가진 옵션 개체를 사용할 수 있습니다.

  • static (boolean): 변경 감지가 실행되기 전에 쿼리를 해결할지 여부(기본값은 false).

Example

다음은 @ContentChild 데코레이터를 사용하여 투영된 컴포넌트를 쿼리하는 예입니다.

1
2
3
<my-component>
<my-child-component></my-child-component>
</my-component>
1
2
3
4
5
6
7
@Component({
selector: 'my-component',
template: ` <ng-content></ng-content> `,
})
export class MyComponent {
@ContentChild(MyChildComponent) myChildComponent!: MyChildComponent;
}

이 예에서 MyComponent 컴포넌트는 해당 콘텐츠에 투영되는 MyChildComponent 인스턴스를 쿼리합니다.

사용 시기

컴포넌트의 콘텐츠에 프로젝션되는 디렉티브나 컴포넌트의 단일 인스턴스를 쿼리해야 하는 경우 @ContentChild 데코레이터를 사용하세요.

Notes

  • 쿼리된 디렉티브 또는 컴포넌트의 여러 인스턴스가 콘텐츠에 프로젝션되는 경우 발견된 첫 번째 인스턴스가 반환됩니다.
  • 쿼리된 디렉티브나 컴포넌트의 인스턴스가 콘텐츠에 프로젝션되지 않으면 쿼리는 undefined를 반환합니다.
  • 정적 옵션이 true로 설정된 경우 변경 감지가 실행되기 전에 쿼리가 해결됩니다. 이는 ngOnInit() 또는 ngAfterViewInit()에서 쿼리된 인스턴스에 액세스해야 하는 경우 유용할 수 있습니다.

@ContentChildren

@ContentChildren 데코레이터는 컴포넌트 또는 디렉티브의 하위 콘텐츠를 쿼리하고 액세스하는 데 사용됩니다. 이를 통해 컴포넌트는 콘텐츠 영역에 프로젝션된 하위 컴포넌트 및 디렉티브에 액세스할 수 있습니다.

데코레이터는 두 가지 인수를 사용합니다.

  • 삽입할 디렉티브를 식별하는 selector 문자열입니다.
  • injection에 대한 추가 옵션을 지정하는 선택적 구성 개체입니다.

다음은 @ContentChildren 데코레이터를 사용하여 투영된 하위 컴포넌트를 쿼리하고 액세스하는 예입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Component, ContentChildren, QueryList } from '@angular/core';
import { TabComponent } from './tab.component';

@Component({
selector: 'app-tabs',
template: ` <ng-content></ng-content> `,
})
export class TabsComponent {
@ContentChildren(TabComponent) tabs: QueryList<TabComponent>;

ngAfterContentInit() {
console.log(this.tabs);
}
}

이 예에서 TabsComponent@ContentChildren 데코레이터를 사용하여 예상되는 모든 TabComponent 하위 항목을 쿼리합니다. 결과 QueryList는 컴포넌트의 tabs 속성에서 사용할 수 있습니다.

ngAfterContentInit 생명주기 훅 메서드는 프로젝션된 콘텐츠가 초기화된 후 tabs 속성에 액세스하는 데 사용됩니다.

기본적으로 @ContentChildren 데코레이터는 요청된 하위 컴포넌트 또는 디렉티브가 처음으로 나타나는 경우만 반환합니다. 모든 항목을 얻으려면 read 옵션을 사용할 수 있습니다.

1
@ContentChildren(TabComponent, { read: ElementRef }) tabs: QueryList<ElementRef>;

이 예제에서는 ElementRef가 읽기 토큰으로 지정되어 @ContentChildren 데코레이터가 TabComponent 대신 ElementRef를 반환하게 됩니다.

전반적으로 @ContentChildren 데코레이터는 Angular 컴포넌트 및 디렉티브의 하위 콘텐츠에 액세스하고 상호 작용하기 위한 강력한 도구입니다.

@Host

@Host 데코레이터는 주어진 토큰과 일치하는 가장 가까운 호스트 요소의 종속성을 주입하는 데 사용됩니다. 이는 하위 요소에 디렉티브를 적용했지만 상위 요소의 속성이나 서비스에 액세스하려는 경우에 특히 유용합니다.

@Host 데코레이터의 사용 예는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { Directive, Host, Optional } from '@angular/core';
import { ParentDirective } from './parent.directive';

@Directive({
selector: '[child]',
})
export class ChildDirective {
constructor(@Host() @Optional() private parentDirective?: ParentDirective) {}

ngOnInit() {
if (this.parentDirective) {
this.parentDirective.doSomething();
}
}
}

위의 예에는 ParentDirective가 적용된 요소의 하위 요소에 적용되는 child 디렉티브가 있습니다. @Host 데코레이터는 ParentDirective가 적용된 가장 가까운 호스트 요소에서 ParentDirective 인스턴스를 주입하는 데 사용됩니다. @Optional 데코레이터는 ParentDirective가 포함된 호스트 요소가 없는 경우 생성자가 오류를 발생시키지 않도록 하는 데 사용됩니다.

@HostListener

@HostListener 데코레이터는 디렉티브의 호스트 요소에 이벤트 리스너를 등록하는 데 사용됩니다. 이 데코레이터는 @Directive 데코레이터의 host 속성과 함께 사용됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Directive, HostListener } from '@angular/core';

@Directive({
selector: '[appMyDirective]',
host: {
'(click)': 'onClick($event)',
},
})
export class MyDirective {
onClick(event: MouseEvent) {
console.log('Clicked!', event);
}
}

이 예에서는 @HostListener 데코레이터가 명시적으로 사용되지 않지만 host 속성에 암시되어 있습니다. 'click' 이벤트는 (click) 구문을 사용하여 onClick() 메서드에 등록됩니다.

@HostListener 데코레이터를 명시적으로 사용할 수도 있습니다.

1
2
3
4
5
6
7
8
9
10
11
import { Directive, HostListener } from '@angular/core';

@Directive({
selector: '[appMyDirective]',
})
export class MyDirective {
@HostListener('click', ['$event'])
onClick(event: MouseEvent) {
console.log('Clicked!', event);
}
}

이 예제에서는 @HostListener 데코레이터를 명시적으로 사용하여 onClick() 메서드에 'click' 이벤트를 등록합니다. '$event' 인수는 이벤트 객체를 메서드에 전달하는 데 사용됩니다.

@HostListener 데코레이터는 클릭 이벤트뿐만 아니라 모든 호스트 요소 이벤트와 함께 사용할 수 있습니다.

@Inject

@Inject 데코레이터를 사용하면 클래스의 종속성을 해결하는 데 사용할 토큰을 지정할 수 있습니다.@Injectable@InjectableProvider와 함께 사용하여 종속성에 대한 custom provider를 제공할 수 있습니다.

예는 다음과 같습니다.

1
2
3
4
5
6
7
8
import { Injectable, Inject } from '@angular/core';
import { ConfigService } from './config.service';
import { AppConfig } from './app.config';

@Injectable()
export class MyService {
constructor(@Inject(ConfigService) private config: AppConfig) {}
}

이 예에서는 ConfigService 토큰과 함께 @Inject 데코레이터를 사용하여 ConfigService 인스턴스를 MyService에 주입합니다. 이는 Angular가 ConfigService 공급자를 사용하여 종속성을 해결하도록 지시합니다.

다음과 같이 문자열 토큰과 함께 @Inject 데코레이터를 사용할 수도 있습니다.

1
2
3
4
5
6
import { Injectable, Inject } from '@angular/core';

@Injectable()
export class MyService {
constructor(@Inject('MY_CONFIG') private config: any) {}
}

이 예에서는 'MY_CONFIG' 토큰과 함께 값을 주입합니다. 원하는 문자열 토큰을 사용할 수 있지만 오타를 방지하려면 상수 값을 사용하는 것이 가장 좋습니다.

전반적으로 @Inject 데코레이터는 애플리케이션의 종속성 주입 동작을 커스터 마이징할 수 있는 강력한 도구입니다.

Share