CHAPTER 9. Building components and directives

Introduction

Component๋Š” ์ง€์‹œ๋ฌธ๊ณผ ์‹ค์ œ๋กœ ๋‹ค๋ฅด์ง€ ์•Š๋‹ค. ๋‹จ์ง€ ๋‘ ๊ฐœ์˜ ์„ ํƒ์  ์†์„ฑ์ด ์žˆ์œผ๋ฉฐ ๊ด€๋ จ ๋ทฐ๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ง€์‹œ์–ด์™€ ๋น„๊ตํ•˜์—ฌ ๋งŽ์€ ์ƒˆ๋กœ์šด ์†์„ฑ์„ ๊ฐ€์ ธ ์˜ค์ง€๋Š” ์•Š๋Š”๋‹ค.

Directives

์ง€์‹œ๋ฌธ์€ Template์ด ์—†๋Š” ๊ฒƒ์„ ์ œ์™ธํ•˜๊ณ ๋Š” ๊ตฌ์„ฑ ์š”์†Œ์™€ ๋งค์šฐ ๋น„์Šทํ•˜๋‹ค. ์‚ฌ์‹ค, Component ํด๋ž˜์Šค๋Š” ํ”„๋ ˆ์ž„ ์›Œํฌ์—์„œ Directive ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•œ๋‹ค. ์ง€์‹œ์–ด ๋ถ„์„์„ ๋จผ์ € ํ•ด๋ณด๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์ง€์‹œ๋ฌธ๊ณผ ๊ด€๋ จํ•˜์—ฌ ์šฐ๋ฆฌ๊ฐ€ ๋ณผ ์ˆ˜์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ์ด ๊ตฌ์„ฑ ์š”์†Œ์—๋„ ์ ์šฉ๋œ๋‹ค. ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๊ตฌ์„ฑ ์˜ต์…˜์„ ์‚ดํŽด ๋ณด๋„๋ก ํ•˜์ž. ๋” ๊ณ ๊ธ‰ ์˜ต์…˜์€ ์ถ”ํ›„์— ๊ธฐ๋ณธ ๋งˆ์Šคํ„ฐ ๋•Œ ์ค€๋น„๊ฐ€๋˜์–ด ์žˆ๋‹ค.

๊ตฌ์„ฑ ์š”์†Œ์˜ ๊ฒฝ์šฐ ์ง€์‹œ๋ฌธ์— ์žฅ์‹์ž๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€๋งŒ @Component ๋Œ€์‹  @Directive๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

์ง€์‹œ์–ด๋Š” ๋งค์šฐ ์ž‘์€ ์˜์—ญ์ด๋ฉฐ HTML์˜ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค. DOM์˜ ์š”์†Œ์— behavior๋ฅผ ์ฒจ๋ถ€ํ•˜๋ฉด ๋œ๋‹ค. ๋™์ผํ•œ ์š”์†Œ์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ง€์‹œ๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ง€์‹œ์–ด์—๋Š” ํ…œํ”Œ๋ฆฟ์—์„œ ํ™œ์„ฑํ™” ํ•  ์œ„์น˜๋ฅผ ํ”„๋ ˆ์ž„ ์›Œํฌ์— ์•Œ๋ ค์ฃผ๋Š” CSS ์„ ํƒ์ž๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

Selectors

์…€๋ ‰ํ„ฐ๋Š” ๋‹ค์–‘ํ•œ ์œ ํ˜•์ด ๋  ์ˆ˜ ์žˆ๋‹ค. โ€ข ์š”์†Œ : ๋Œ€๊ฐœ ๊ตฌ์„ฑ ์š”์†Œ์˜ ๊ฒฝ์šฐ์ฒ˜๋Ÿผ ๋ฐ”๋‹ฅ ๊ธ€ : footer. โ€ข ๋นˆ๋ฒˆํ•˜์ง€๋Š” ์•Š์€ class.: .alert โ€ข ์ง€์‹œ์–ด์— ๊ฐ€์žฅ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ์†์„ฑ : [color]. โ€ข ํŠน์ • ๊ฐ’์„ ๊ฐ–๋Š” ์†์„ฑ : [color = red]. โ€ข ์œ„์˜ ์กฐํ•ฉ : footer [color = red]๋Š” ๊ฐ’์ด ๋นจ๊ฐ„์ƒ‰ ์ธ ์†์„ฑ ์ƒ‰์„ ๊ฐ€์ง„ footer ๋ผ๋Š” ์š”์†Œ์™€ ์ผ์น˜ํ•œ๋‹ค. [color], footer.alert๋Š” color ์†์„ฑ์„ ๊ฐ€์ง„ ๋ชจ๋“  ์š”์†Œ ๋˜๋Š” footer๋ผ๋Š” ์š”์†Œ๋ฅผ CSS ํด๋ž˜์Šค alert๊ณผ ์ผ์น˜ ์‹œํ‚จ๋‹ค. footer : not (.alert)๋Š” CSS ํด๋ž˜์Šค ๊ฒฝ๊ณ ๊ฐ€ ์—†๋Š” (: not ()) footer๋ผ๋Š” ์š”์†Œ๋ฅผ ์ฐพ๋Š”๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์ด๊ฒƒ์€ ์•„๋ฌด๊ฒƒ๋„ํ•˜์ง€ ์•Š๊ณ  ์†์„ฑ doNothing์ด ์š”์†Œ์—์žˆ์„ ๊ฒฝ์šฐ ํ™œ์„ฑํ™”๋˜๋Š” ๋งค์šฐ ๊ฐ„๋‹จํ•œ ์ง€์‹œ์–ด ์ด๋‹ค.

@Directive({
  selector: '[doNothing]'
})
export class DoNothingDirective {
  constructor() {
   console.log('Do nothing directive');
  }
}

๊ทธ๋Ÿฌํ•œ ์ง€์‹œ์ž๋Š” ์ด TestComponent์™€ ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ™œ์„ฑํ™” ๋  ๊ฒƒ์ด๋‹ค.

@Component({
  selector: 'ns-test',
  template: '<div doNothing>Click me</div>'
})
export class TestComponent {
}

๋” ๋ณต์ž‘ํ•ฉ ์„ ํƒ์ž๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.

@Directive({
  selector: 'div.loggable[logText]:not([notLoggable=true])'
})
export class ComplexSelectorDirective {
  constructor() {
   console.log('Complex selector directive');
  }
}

์—ฌ๊ธฐ์„œ๋Š” ๋ชจ๋“  div ์š”์†Œ๋ฅผ loggable ํด๋ž˜์Šค์™€ ์ผ์น˜ ์‹œํ‚ค๋ฉฐ logText ์†์„ฑ์€ true ๊ฐ’์„ ๊ฐ€์ง„ notLoggable ์†์„ฑ์„ ๊ฐ–์ง€ ์•Š๋Š”๋‹ค.

<div class="loggable" logText="text">Hello</div>

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ํ•œ ๊ฐ€์ง€๊ฐ€ ์•„๋‹๊ฒƒ์ด๋‹ค.

<div class="loggable" logText="text" notLoggable="true">Hello</div>

์†”์งํ•˜๊ฒŒ ๋งŒ์•ฝ ๋‹น์‹ ์ด ์ด๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•œ๋‹ค๋ฉด ์ž˜๋ชป ์‚ฌ์šฉ๋œ ๊ฒƒ์ด๋‹ค.

์ž์†, ํ˜•์ œ, ids, ์™€์ผ๋“œ ์นด๋“œ ๋ฐ ์˜์‚ฌ (์˜ˆ : not ์ด์™ธ)์™€ ๊ฐ™์€ CSS ์„ ํƒ๊ธฐ๋Š” ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์†์„ฑ ์„ ํƒ์ž๋ฅผ bind-, on-, let- ๋˜๋Š” ref-๋กœ ์‹œ์ž‘ํ•˜๋ฉด ์•ˆ๋œ๋‹ค. : ํŒŒ์„œ์— ๋”ฐ๋ผ์„œ ๋‹ค๋ฅธ ์˜๋ฏธ๋ฅผ ๊ฐ€์ง„๋‹ค. ์™œ๋ƒํ•˜๋ฉด ํ‘œ์ค€ ํ…œํ”Œ๋ฆฟ ๊ตฌ๋ฌธ์˜ ์ผ๋ถ€ ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

Inputs

๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๊ตฌ์„ฑ ์š”์†Œ ๋˜๋Š” ์ง€์‹œ๋ฌธ์„ ๋งŒ๋“œ๋Š” ์ž‘์—…์˜ ํฐ ๋ถ€๋ถ„์ผ ๊ฒƒ์ด๋‹ค. ์ƒ์œ„ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ํ•˜์œ„ ์š”์†Œ ์ค‘ ํ•˜๋‚˜์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ๋•Œ๋งˆ๋‹ค ์†์„ฑ ๋ฐ”์ธ๋”ฉ์„ ์‚ฌ์šฉํ•œ๋‹ค.

์ด๋ฅผ ์œ„ํ•ด @Directive ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ inputs ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ํ—ˆ์šฉํ•˜๋Š” ๋ชจ๋“  ์†์„ฑ์„ ์ •์˜ํ•œ๋‹ค. ์ด ์†์„ฑ์€ ๊ฐ๊ฐ์˜ property : binding ์–‘์‹ ๋ฌธ์ž์—ด ๋ฐฐ์—ด์„ ๋ฐ›์•„ ๋“ค์ธ๋‹ค. property๋Š” ์ง€์‹œ์–ด ์ธ์Šคํ„ด์Šค ์†์„ฑ์„ ๋‚˜ํƒ€๋‚ด๊ณ  binding์€ ํ‘œํ˜„์‹์„ ํฌํ•จ ํ•  DOM ์†์„ฑ์ด๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์ด ์ง€์‹œ๋ฌธ์€ DOM ์†์„ฑ logText๋ฅผ ์ง€์‹œ๋ฌธ ์ธ์Šคํ„ด์Šค ์†์„ฑ ํ…์ŠคํŠธ์— ๋ฐ”์ธ๋”ฉํ•œ๋‹ค.

@Directive({
  selector: '[loggable]',
  inputs: ['text: logText']
})
export class SimpleTextDirective {
}

๋‹น์‹ ์˜ ์ง€์‹œ์–ด์— ์†์„ฑ์ด ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋Š” ๊ทธ๊ฒƒ์ด ์ƒ์„ฑ๋œ๋‹ค. ๋‹ค์Œ์€ ์ž…๋ ฅ์ด ๋ณ€๊ฒฝ ๋  ๋•Œ๋งˆ๋‹ค ์†์„ฑ์ด ์ž๋™์œผ๋กœ ์—…๋ฐ์ดํŠธ ๋œ๋‹ค.

<div loggable logText="Some text">Hello</div>

์†์„ฑ์ด ๋ณ€๊ฒฝ ๋  ๋•Œ ์•Œ๋ฆผ์„ ๋ฐ›์œผ๋ ค๋ฉด ์ง€์นจ์— setter ๋ฅผ ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋‹ค. setter๋Š” logText ์†์„ฑ์ด ๋ณ€๊ฒฝ ๋  ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋œ๋‹ค.

@Directive({
  selector: '[loggable]',
  inputs: ['text: logText']
})
export class SimpleTextWithSetterDirective {
  set text(value) {
   console.log(value);
  }
}

๋งŒ์•ฝ ๋‹น์‹ ์ด ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•œ๋‹ค๋ฉด

<div loggable logText="Some text">Hello</div>
// our directive will log "Some text"

๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ ํ…์ŠคํŠธ๋Š” ์ •์ ์ด์ง€๋งŒ ๋ฌผ๋ก  ๋ณด๊ฐ„๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ ์‰ฝ๊ฒŒ ๋™์ ์ธ ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

<div loggable logText="{{expression}}">Hello</div>
// our directive will log the value of 'expression' in the component

๋˜๋Š” ๋Œ€๊ด„ํ˜ธ ๊ตฌ๋ฌธ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

<div loggable [logText]="expression">Hello</div>
// our directive will log the value of 'expression' in the component

์ด๊ฒƒ์€ ์ƒˆ๋กœ์šด ํ…œํ”Œ๋ฆฟ ๊ตฌ๋ฌธ์˜ ๊ฐ€์žฅ ํฐ ํŠน์ง• ์ค‘ ํ•˜๋‚˜์ด๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ ๊ฐœ๋ฐœ์ž๋Š” ๊ตฌ์„ฑ ์š”์†Œ์˜ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์— ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๊ณ  ๋ฐ”์ธ๋”ฉ ํ•  ์†์„ฑ์„ ์ •์˜ํ•œ๋‹ค. (์ผ๋ถ€ AngularJS 1.x๋ฅผ ์ž‘์„ฑํ•œ ๊ฒฝ์šฐ ์•ฝ๊ฐ„ ์”ฉ '@'๋ฐ '='๊ตฌ๋ฌธ์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.)

๋ฐ”์ธ๋”ฉ์— ํŒŒ์ดํ”„๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ๋„ ์žˆ๋‹ค.

<div loggable [logText]="expression | uppercase">Hello</div>
// our directive will log the value of 'expression' in the component in uppercase

DOM ์†์„ฑ์„ ๋™์ผํ•œ ์ด๋ฆ„์„ ๊ฐ€์ง„ ์ง€์‹œ์–ด์˜ ์†์„ฑ์— ๋ฐ”์ธ๋”ฉ ํ•˜๋ ค๋ฉด property : binding ๋Œ€์‹  ์†์„ฑ์„ ์“ธ ์ˆ˜ ์žˆ๋‹ค.

@Directive({
  selector: '[loggable]',
  inputs: ['logText']
})
export class SameNameInputDirective {
  set logText(value) {
   console.log(value);
  }
}
<div loggable logText="Hello">Hello</div>
// our directive will log "Hello"

์ง€์‹œ์–ด์— @Input ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž…๋ ฅ์„ ์„ ์–ธํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์„ ๊ฐ€์žฅ ์„ ํ˜ธ ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ๋งŽ์€ ์˜ˆ์ œ๋“ค์ด ์ง€๊ธˆ๋ถ€ํ„ฐ ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด์ง€๋งŒ, ๋‹น์‹ ์ด ์„ ํ˜ธํ•˜๋Š” ๊ฒƒ์„ ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

@Directive({
  selector: '[loggable]'
})
export class InputDecoratorDirective {
  @Input('logText') text: string;
}

๋˜๋Š” ๊ฐ™์€ ์˜๋ฏธ์˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

@Directive({
  selector: '[loggable]'
})
export class SameNameInputDecoratorDirective {
  @Input() logText: string;
}

์ด ์ž‘์—…์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ๊ฐ™์€ ์ด๋ฆ„์˜ ํ•„๋“œ์™€ ์„ค์ •์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด TypeScript ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์˜ค๋ฅ˜๋กœ ํŒ๋‹จ ํ•  ์ˆ˜ ์žˆ๋‹ค. setter๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ˆ˜์ •ํ•˜๋Š” ํ•œ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์€ ํ•ญ์ƒ ํ•„์š”ํ•˜์ง€๋Š” ์•Š์ง€๋งŒ @Input ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ setter์— ์ง์ ‘ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

@Directive({
  selector: '[loggable]'
})
export class InputDecoratorOnSetterDirective {
  @Input('logText')
  set text(value) {
   console.log(value);
  }
}

๋˜๋Š” setter ๊ทธ๋ฆฌ๊ณ  ๋ฐ”์ธ๋”ฉ ์ด๋ฆ„์„ ๊ฐ™์ด ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค.

@Directive({
  selector: '[loggable]'
})
export class SameNameInputDecoratorOnSetterDirective {
  @Input()
  set logText(value) {
   console.log(value);
  }
}

์ž…๋ ฅ์€ ์ƒ๋‹จ ์š”์†Œ์—์„œ ํ•˜๋‹จ ์š”์†Œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐ ํšจ๊ณผ์ ์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์กฐ๋ž‘๋ง ๋ชฉ๋ก์„ ํ‘œ์‹œํ•˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์›ํ•  ๊ฒฝ์šฐ ๋ชฉ๋ก์ด ํฌํ•จ ๋œ ์ƒ์œ„ ๊ตฌ์„ฑ ์š”์†Œ์™€ ์กฐ๋ž‘๋ง์„ ํ‘œ์‹œํ•˜๋Š” ๋‹ค๋ฅธ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์žˆ์„ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.

@Component({
  selector: 'ns-pony',
  template: `<div>{{pony.name}}</div>`
})
export class PonyComponent {
  @Input() pony: Pony;
}
@Component({
  selector: 'ns-ponies',
  template: `<div>
   <h2>Ponies</h2>
   // the pony is handed to PonyComponent via [pony]="currentPony"
   <ns-pony *ngFor="let currentPony of ponies" [pony]="currentPony"></ns-pony>
  </div>`
})
export class PoniesComponent {
  ponies: Array<Pony> = [
   { id: 1, name: 'Rainbow Dash' },
   { id: 2, name: 'Pinkie Pie' }
  ];
}

Outputs

์ตœ๊ทผ ์˜ˆ์ œ๋กœ ๋Œ์•„๊ฐ€์„œ ์กฐ๋ž‘๋ง์„ ํด๋ฆญํ•˜์—ฌ ์„ ํƒํ•˜๊ณ  ์ƒ์œ„ ๊ตฌ์„ฑ ์š”์†Œ์— ์•Œ๋ฆฌ๊ณ  ์‹ถ๋‹ค๊ณ  ํ•ฉ์‹œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ๋งž์ถค ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒƒ์€ ์ค‘์š”ํ•˜๋‹ค. Angular 2์—์„œ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์†์„ฑ์„ ํ†ตํ•ด ๊ตฌ์„ฑ ์š”์†Œ๋กœ ์œ ์ž…๋˜๊ณ  ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•ด ๊ตฌ์„ฑ ์š”์†Œ ๋ฐ–์œผ๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ปค์Šคํ…€ ์ด๋ฒคํŠธ๋Š” EventEmitter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฉ์ถœ ๋˜๋ฉฐ, outputs ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์—์„œ ์„ ์–ธ ๋˜์–ด์•ผ ํ•œ๋‹ค. inputs ์†์„ฑ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ์ง€์‹œ์–ด / ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ๋‚ด ๋ณด๋‚ด๋ ค๋Š” ์ด๋ฒคํŠธ ๋ชฉ๋ก์ด ์žˆ๋Š” ๋ฐฐ์—ด์„ ํ—ˆ์šฉํ•œ๋‹ค.

ponySelected๋ผ๋Š” ์ด๋ฒคํŠธ๋ฅผ ๋‚ด๋ณด๋‚ด๋ ค๊ณ  ํ•œ๋‹ค๊ณ  ๊ฐ€์ • ํ•ด ๋ด…์‹œ๋‹ค. ์šฐ๋ฆฌ๋Š” ํ•  ์ผ์ด ์„ธ ๊ฐ€์ง€ ์žˆ๋‹ค. โ€ข ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์—์„œ ์ถœ๋ ฅ์„ ์„ ์–ธํ•œ๋‹ค. โ€ข EventEmitter ๋งŒ๋“ค๊ธฐ โ€ข ์กฐ๋ž‘๋ง์„ ์„ ํƒํ•˜๋ฉด ์ด๋ฒคํŠธ๋ฅผ ๋ฐฉ์ถœํ•œ๋‹ค.

@Component({
  selector: 'ns-pony',
  inputs: ['pony'],
  // we declare the custom event as an output
  outputs: ['ponySelected'],
  // the method `selectPony()` will be called on click
  template: `<div (click)="selectPony()">{{pony.name}}</div>`
})
export class SelectablePonyComponent {
  pony: Pony;
  // the EventEmitter is used to emit the event
  ponySelected = new EventEmitter<Pony>();
  /**
  * Selects a pony when the component is clicked.
  * Emits a custom event.
  */
  selectPony() {
   this.ponySelected.emit(this.pony);
  }
}

ํ…œํ”Œ๋ฆฟ์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋ฉด :

<ns-pony [pony]="pony" (ponySelected)="betOnPony($event)"></ns-pony>

์œ„์˜ ์˜ˆ์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์กฐ๋ž‘๋ง ์ด๋ฆ„์„ ํด๋ฆญ ํ•  ๋•Œ๋งˆ๋‹ค ํฌ๋‹ˆ ๊ฐ’ (emit () ๋ฉ”์†Œ๋“œ์˜ ๋งค๊ฐœ ๋ณ€์ˆ˜)๋กœ ์ด๋ฒคํŠธ ponySelected๋ฅผ ํ˜ธ์ถœ ํ•  ๊ฒƒ์ด๋‹ค. ๋ถ€๋ชจ ์š”์†Œ๋Š” ํ…œํ”Œ๋ฆฟ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ์ด ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ  ์žˆ๋‹ค. ์ด๋ฒคํŠธ $ event ๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ betOnPony ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. $ event๋Š” ๋‹น์‹ ์ด ๋ฐฉ์ถœ ํ•œ ์ด๋ฒคํŠธ์— ์•ก์„ธ์Šคํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค : ์—ฌ๊ธฐ์—์„œ ๋ฐฉ์ถœ๋˜๋Š” ๊ฐ’์€ ์กฐ๋ž‘๋ง์ด๋‹ค.

๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ถ€๋ชจ ๊ตฌ์„ฑ ์š”์†Œ์—๋Š” betOnPony () ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๋ฉฐ, ์„ ํƒํ•œ ์กฐ๋ž‘๋ง๊ณผ ํ•จ๊ป˜ ํ˜ธ์ถœ ๋œ๋‹ค.

betOnPony(pony) {
  // do something with the pony
}

์›ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” emitter: event ์™€ ๊ฐ™์ด emiiter์™€ ๋‹ค๋ฅธ ์ด๋ฒคํŠธ ์ด๋ฆ„์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

@Component({
  selector: 'ns-pony',
  inputs: ['pony'],
  // the emitter is called `emitter`
  // and the event `ponySelected`
  outputs: ['emitter: ponySelected'],
  template: `<div (click)="selectPony()">{{pony.name}}</div>`
})
export class OtherSelectablePonyComponent {
  pony: Pony;
  emitter = new EventEmitter<Pony>();
  selectPony() {
   this.emitter.emit(this.pony);
  }
}

์ž…๋ ฅ์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฒคํŠธ๋ฅผ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ๋‹น์‹ ์ด ์›ํ•˜๋Š” ๊ฒƒ์„ ์„ ํƒํ•ด์„œ ์„ ์–ธํ•˜๋ฉด ๋œ๋‹ค.

@Component({
  selector: 'ns-pony',
  template: `<div (click)="selectPony()">{{pony.name}}</div>`
})
export class SelectablePonyWithDecoratorComponent {
  @Input() pony: Pony;
  @Output() ponySelected = new EventEmitter<Pony>();
  selectPony() {
   this.ponySelected.emit(this.pony);
  }
}

Lifecycle

๋‹น์‹ ์˜ ์ง€์‹œ์ž๊ฐ€ ๊ทธ ์‚ถ์˜ ํŠน์ • ์ˆœ๊ฐ„์— ๋ฐ˜์‘ํ•˜๋Š” ๊ฒƒ์„ ๋ฐ”๋ž„์ง€๋„ ๋ชจ๋ฅธ๋‹ค. ๊ณ ๊ธ‰ ์˜ต์…˜์œผ๋กœ ๋งค๋ฒˆ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋‚˜๋Š” ๋นจ๋ฆฌ ๋„˜๊ธธ ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์ž…๋ ฅ์ด ์ƒ์„ฑ์ž์—์„œ ์•„์ง ํ‰๊ฐ€ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ƒ๋‹นํ•œ ์‹œ๊ฐ„์„ ์ ˆ์•ฝ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฆ‰, ๋‹ค์Œ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค.

@Directive({
  selector: '[undefinedInputs]'
})
export class UndefinedInputsDirective {
  @Input() pony: string;
  constructor() {
   console.log(`inputs are ${this.pony}`);
   // will log "inputs are undefined", always
  }
}

์˜ˆ๋ฅผ ๋“ค์–ด ์ž…๋ ฅ ๊ฐ’์— ์•ก์„ธ์Šคํ•˜์—ฌ ์„œ๋ฒ„์—์„œ ์ถ”๊ฐ€์ ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜๋ ค๋ฉด ๋ผ์ดํ”„ ์‚ฌ์ดํด ๋‹จ๊ณ„๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ž์ฒด์ ์ธ ํŠน์ˆ˜์„ฑ์ด ์žˆ๋‹ค.

โ€ข ๋ฐ”์ธ๋”ฉ ๋œ ์†์„ฑ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด ngOnChanges๊ฐ€ ๋จผ์ € ํ˜ธ์ถœ๋  ๊ฒƒ์ด๋‹ค. SimpleChange์—์„œ ๋ฐ”์ธ๋”ฉ๋œ ํ˜„์žฌ ๊ฐ’๊ณผ ์ด์ „ ๊ฐ’์ด ํฌํ•จ ๋œ ์ˆ˜์ • ๋งต์„ ํ™•์ธํ•œ๋‹ค. ํ™•์ธ ํ›„์— ๋ณ€๊ฒฝ์ด ์—†์œผ๋ฉด ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค. โ€ข ngOnInit ์ฒซ ๋ฒˆ์งธ ๋ณ€๊ฒฝ ํ›„ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ ๋œ๋‹ค. (ngOnChanges๋Š” ๋ชจ๋“  ๋ณ€๊ฒฝ์„ ํ˜ธ์ถœํ•œ๋‹ค). ์ด ๋‹จ๊ณ„๋Š” ์ด๋ฆ„์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด ์ดˆ๊ธฐํ™” ์ž‘์—…์— ์ตœ์ ์ด๋‹ค. โ€ข ngOnDestroy ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์ œ๊ฑฐ ๋  ๋•Œ ํ˜ธ์ถœ ๋œ๋‹ค. ์ •๋ฆฌํ•˜๋Š” ์‹œ์ ์— ๋งค์šฐ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋œ๋‹ค.

๋‹ค๋ฅธ ๋‹จ๊ณ„๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ณ ๊ธ‰ ์˜ต์…˜์ด๋‹ค.

โ€ข ngDoCheck๋Š” ์•ฝ๊ฐ„ ๋‹ค๋ฅด๋‹ค. ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ, ๊ฐ ๋ณ€๊ฒฝ ๊ฒ€์ƒ‰ ์ฃผ๊ธฐ์— ๋ถˆ๋ ค ๊ธฐ๋ณธ ๋ณ€๊ฒฝ ๊ฐ์ง€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์žฌ์ •์˜ํ•œ๋‹ค. ์ฆ‰, ๋ฐ”์ธ๋”ฉ ๋œ ์†์„ฑ ๊ฐ„์˜ ์ฐจ์ด๋ฅผ ์ฐพ๋Š”๋‹ค. ๊ฐ’. ์ฆ‰, ์ ์–ด๋„ ํ•˜๋‚˜์˜ ์ž…๋ ฅ์ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ”„๋ ˆ์ž„ ์›Œํฌ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋ณ€๊ฒฝ๋œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋˜๊ณ , ๊ทธ ์•„์ด๋Š” ํ™•์ธ ๋œ ๋ Œ๋”๋ง์ด ๋œ๋‹ค. ํ•˜์ง€๋งŒ ์ž…๋ ฅ์ด ๋ณ€๊ฒฝ ๋˜์–ด๋„ ํšจ๊ณผ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ ์žˆ๋Š” ๊ฒฝ์šฐ๋Š” ๊ทธ๊ฒƒ์„ ํ•ด์ œ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒƒ์€ ๊ธฐ๋ณธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ตœ์†Œ ๊ฐ’์„ ํ™•์ธํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ๋ณ€๊ฒฝ ๊ฐ์ง€ ์†๋„ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์œ ์šฉํ•˜์ง€๋งŒ, ์ผ๋ฐ˜์ ์œผ๋กœ ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. โ€ข ngAfterContentInit ๊ตฌ์„ฑ ์š”์†Œ์˜ ๋ชจ๋“  ๋ฐ”์ธ๋”ฉ์ด ์ฒ˜์Œ ํ™•์ธ ๋œ ๊ฒฝ์šฐ์— ํ˜ธ์ถœ๋œ๋‹ค. โ€ข ngAfterContentChecked ๊ตฌ์„ฑ ์š”์†Œ์˜ ๋ชจ๋“  ๋ฐ”์ธ๋”ฉ์ด ํ™•์ธ ๋œ ๋•Œ ํ˜ธ์ถœ๋œ๋‹ค. ๊ทธ๋“ค์€ ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค. โ€ข ngAfterViewInit ์ž์‹ ์ง€์‹œ๋ฌธ์˜ ๋ฐ”์ธ๋”ฉ์ด ๋จผ์ € ํ™•์ธ ๋œ ๊ฒฝ์šฐ์— ํ˜ธ์ถœ๋œ๋‹ค. โ€ข ngAfterViewChecked ์ž์‹ ์ง€์‹œ๋ฌธ์˜ ๋ฐ”์ธ๋”ฉ์ด ์ฒดํฌ ๋˜์–ด์žˆ์„ ๋•Œ ๋ถˆ๋ ค ๋น„๋ก ๋ณ€ํ™”ํ•˜์ง€ ์•Š๊ณ . ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ํ•˜์œ„ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒฝ์šฐ์— ์œ ์šฉํ•˜๋‹ค. ngAfterViewInit ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ตฌ์„ฑ ์š”์†Œ์— ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉด ์˜๋ฏธ๊ฐ€ ์žˆ๋‹ค.

์ด์ „ ์ƒ˜ํ”Œ์€ ngOnInit์„ ์‚ฌ์šฉํ•˜์—ฌ ๋” ์ž˜ ๋™์ž‘ํ•œ๋‹ค. Angular 2๋Š” ngOnInit () ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฏ€๋กœ ์ง€์‹œ๋ฌธ์— ์ด ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ๋œ๋‹ค. ๋ชจ๋ฐ”์ผ์šฉ TypeScript๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ธํ„ฐํŽ˜์ด์Šค OnInit์„ ํ™œ์šฉํ•˜์—ฌ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

@Directive({
  selector: '[initDirective]'
})
export class OnInitDirective implements OnInit {
  @Input() pony: string;
  ngOnInit() {
   console.log(`inputs are ${this.pony}`);
   // inputs are not undefined \o/
  }
}

์ด์ œ ์šฐ๋ฆฌ์˜ input ํƒœ๊ทธ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. ์†์„ฑ์ด ๋ณ€๊ฒฝ ๋  ๋•Œ๋งˆ๋‹ค ๋ฌด์–ธ๊ฐ€๋ฅผ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ngOnChanges๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ๋ผ.

@Directive({
  selector: '[changeDirective]'
})
export class OnChangesDirective implements OnChanges {
  @Input() pony: string;
  ngOnChanges(changes: SimpleChanges) {
   const ponyValue = changes['pony'];
   console.log(`changed from ${ponyValue.previousValue} to ${ponyValue.currentValue}`);
   console.log(`is it the first change? ${ponyValue.isFirstChange()}`);
  }
}

๋ณ€๊ฒฝ ๋งค๊ฐœ ๋ณ€์ˆ˜๋Š” ๋ฐ”์ธ๋”ฉ ์ด๋ฆ„์„ ํ‚ค๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋งต์ด๋ฉฐ ๋‘ ์†์„ฑ (์ด์ „ ๊ฐ’๊ณผ ํ˜„์žฌ ๊ฐ’)์„ ๊ฐ’์œผ๋กœ ๊ฐ–๋Š” SimpleChange ๊ฐ์ฒด๋Š” ๋ฌผ๋ก  isFirstChange () ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์•Œ๊ธฐ์œ„ํ•œ ์ฒซ ๋ฒˆ์งธ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด๋‹ค. ๋ฐ”์ธ๋”ฉ ์ค‘ ํ•˜๋‚˜์˜ ๋ณ€๊ฒฝ์—๋งŒ ๋ฐ˜์‘ํ•˜๋ ค๋ฉด setter๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ๋‹ค์Œ ์˜ˆ์ œ๋Š” ์ด์ „ ์ถœ๋ ฅ๊ณผ ๋™์ผํ•œ ์ถœ๋ ฅ์„ ์ƒ์„ฑํ•œ๋‹ค.

@Directive({
  selector: '[setterDirective]',
  inputs: ['pony']
})
export class SetterDirective {
  private ponyModel: string;
  set pony(newPony) {
   console.log(`changed from ${this.ponyModel} to ${newPony}`);
   this.ponyModel = newPony;
  }
}

ngOnChanges๋Š” ๋™์‹œ์— ์—ฌ๋Ÿฌ ๋ฐ”์ธ๋”ฉ์„ ๋ณผ ๋•Œ ์œ ์šฉํ•˜๋‹ค. ํ•˜๋‚˜ ์ด์ƒ์˜ ๋ฐ”์ธ๋”ฉ์ด ๋ณ€๊ฒฝ๋˜๊ณ  ๋ณ€๊ฒฝ๋œ ์†์„ฑ๋งŒ ํฌํ•จํ•˜๋Š” ๊ฒฝ์šฐ์— ํ˜ธ์ถœ๋œ๋‹ค.

ngOnDestroy ๋‹จ๊ณ„๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์„ ์ทจ์†Œํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ •๋ฆฌํ•˜๋Š” ๋ฐ ์ ํ•ฉํ•˜๋‹ค. ์—ฌ๊ธฐ์—์„œ OnDestroyDirective๋Š” ์ƒ์„ฑ ๋  ๋•Œ๋งˆ๋‹ค "hello"๋ฅผ ๊ธฐ๋กํ•œ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ํŽ˜์ด์ง€์—์„œ ์ œ๊ฑฐ๋˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ถœ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด setInterval์„ ์ค‘์ง€ํ•˜๋ ค๊ณ  ํ•œ๋‹ค.

@Directive({
  selector: '[destroyDirective]'
})
export class OnDestroyDirective implements OnDestroy {
  sayHello: number;
  constructor() {
   this.sayHello = window.setInterval(() => console.log('hello'), 1000);
  }
  ngOnDestroy() {
   window.clearInterval(this.sayHello);
  }
}

Providers

Dependency Injection ์žฅ์˜ ๊ณต๊ธ‰์ž์— ๊ด€ํ•ด ์ด๋ฏธ ์ด์•ผ๊ธฐ ํ•œ์ ์ด ์žˆ๋‹ค. ์ด ์†์„ฑ์€ ํ˜„์žฌ ์ง€์‹œ์–ด์™€ ๊ทธ ์ž์‹์— ์ฃผ์‚ฌ ํ•  ์ˆ˜์žˆ๋Š” ์„œ๋น„์Šค๋ฅผ ์„ ์–ธ ํ•  ์ˆ˜์žˆ๊ฒŒ ํ•œ๋‹ค.

@Directive({
  selector: '[providersDirective]',
  providers: [PoniesService]
})
export class ProvidersDirective {
  constructor(poniesService: PoniesService) {
   const ponies = poniesService.list();
   console.log(`ponies are: ${ponies}`);
  }
}

Components

Component๋Š” ์ง€์‹œ๋ฌธ๊ณผ ์‹ค์ œ๋กœ ๋‹ค๋ฅด์ง€ ์•Š๋‹ค. ๋‹จ์ง€ ๋‘ ๊ฐœ์˜ ์„ ํƒ์  ์†์„ฑ์ด ์žˆ์œผ๋ฉฐ ๊ด€๋ จ ๋ทฐ๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ง€์‹œ์–ด์™€ ๋น„๊ตํ•˜์—ฌ ๋งŽ์€ ์ƒˆ๋กœ์šด ์†์„ฑ์„ ๊ฐ€์ ธ ์˜ค์ง€๋Š” ์•Š๋Š”๋‹ค.

View providers

์šฐ๋ฆฌ๋Š” ๊ณต๊ธ‰์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ •ํ•œ ์ฃผ์ž…์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜์˜€๋‹ค. viewProviders๋Š” ๋งค์šฐ ์œ ์‚ฌํ•˜๋‚˜ provider๋“ค์€ ํ˜„์žฌ ์ปดํฌ๋„ŒํŠธ์— ํ—ˆ์šฉ๋˜์ง€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๋Š” ์œ ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

Template / Template URL

์šฐ๋ฆฌ๋Š” ๊ณต๊ธ‰์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ •ํ•œ ์ฃผ์ž…์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜์˜€๋‹ค. viewProviders๋Š” ๋งค์šฐ ์œ ์‚ฌํ•˜๋‚˜ provider๋“ค์€ ํ˜„์žฌ ์ปดํฌ๋„ŒํŠธ์— ํ—ˆ์šฉ๋˜์ง€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๋Š” ์œ ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. @Component์˜ ์ฃผ์š” ๊ธฐ๋Šฅ์€ ํ…œํ”Œ๋ฆฟ์„ ๊ฐ–๋Š” ๋ฐ˜๋ฉด ์ง€์‹œ๋ฌธ์—๋Š” ํ…œํ”Œ๋ฆฟ์ด ์—†๋Š” ๊ฒƒ์ด ์ฐจ์ด ์ด๋‹ค. ํ…œํ”Œ๋ฆฟ์„ ์ธ๋ผ์ธ์œผ๋กœ ์„ ์–ธํ•˜๊ฑฐ๋‚˜ templateURL์„ ์‚ฌ์šฉํ•˜์—ฌ URL์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ„๋„์˜ ํŒŒ์ผ์— ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค. (๋‹จ, ๋™์‹œ์— ๋‘˜ ๋‹ค ํ•  ์ˆ˜๋Š” ์—†๋‹ค)

์ผ๋ฐ˜์ ์œผ๋กœ ํ…œํ”Œ๋ฆฟ์ด ์ž‘์œผ๋ฉด (1-2 ์ค„) ์ธ๋ผ์ธ์œผ๋กœ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚ซ๋‹ค. ์ฝ”๋“œ๊ฐ€ ๋Š˜์–ด๋‚˜๊ธฐ ์‹œ์ž‘ํ•˜๋ฉด ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋ณต์žกํ•ด์ง€์ง€ ์•Š๋„๋ก ํŒŒ์ผ์„ ์ž์ฒด ํŒŒ์ผ๋กœ ์ด๋™ํ•˜์—ฌ๋ผ. URL, ์ƒ๋Œ€ URL ๋˜๋Š” ์ „์ฒด HTTP URL์— ๋Œ€ํ•ด ์ ˆ๋Œ€ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋กœ๋“œ ๋˜๋ฉด Angular 2๊ฐ€ URL์„ ํ™•์ธํ•˜๊ณ  ํ…œํ”Œ๋ฆฟ์„ ๊ฐ€์ ธ ์˜ค๋ ค๊ณ  ์‹œ๋„ํ•œ๋‹ค. ์„ฑ๊ณตํ•  ๊ฒฝ์šฐ ํ…œํ”Œ๋ฆฟ์€ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์„€๋„์šฐ ๋ฃจํŠธ์ด๋ฉฐ ํ•ด๋‹น ํ‘œํ˜„์‹์ด ํ‰๊ฐ€ ๋œ๋‹ค. ํฐ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ผ๋ฐ˜์ ์œผ๋กœ ํ…œํ”Œ๋ฆฟ์„ ๊ฐ™์€ ํด๋”์˜ ๋ณ„๋„ ํŒŒ์ผ์— ์ €์žฅํ•˜๊ณ  ์ƒ๋Œ€ URL์„ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๋“œํ•œ๋‹ค.

@Component({
  selector: 'ns-templated-pony',
  templateUrl: 'components/pony/templated-pony.html'
})
export class TemplatedPonyComponent {
  @Input() pony: any;
}

์ƒ๋Œ€ URL์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ URL์€ ์•ฑ์˜ ๊ธฐ๋ณธ URL์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐ๋œ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์„ฑ ์š”์†Œ / ํฌ๋‹ˆ์— ์žˆ์œผ๋ฉด ํ…œํ”Œ๋ฆฟ URL์€ components / pony / pony.html์ด ๋˜๋ฏ€๋กœ URL์ด ๋ฒˆ๊ฑฐ๋กœ์šธ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ moduleId ๋“ฑ๋ก ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ CommonJS ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ํŒจํ‚ค์ง€ํ•˜๋ฉด ์•ฝ๊ฐ„ ๋” ์ž˜ ์ˆ˜ํ–‰ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฐ’์€ CommonJS๊ฐ€ ๋Ÿฐํƒ€์ž„์— ์„ค์ •ํ•˜๋Š” ๊ฐ’์ธ module.id ์ด๋‹ค. Angular 2๋Š”์ด ๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ ์ •ํ™•ํ•œ ์ƒ๋Œ€ URL์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ํ…œํ”Œ๋ฆฟ URL์€ ์ด์ œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ผ ๊ฒƒ ์ด๋‹ค.

@Component({
  selector: 'ns-templated-pony',
  templateUrl: 'templated-pony.html',
  moduleId: module.id
})
export class ModuleIdPonyComponent {
  @Input() pony: any;
}

๊ทธ๋ฆฌ๊ณ  ๊ตฌ์„ฑ ์š”์†Œ์™€ ๋™์ผํ•œ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ํ…œํ”Œ๋ฆฟ์„ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค! ๋” ๋‚˜์€ ์ ์€ : Web-Pack์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, ์•ฝ๊ฐ„์˜ ์„ค์ • (์ด๋ฏธ Angular-Cli๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.)์œผ๋กœ module.id๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์ง์ ‘ ์ƒ๋Œ€ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. Webpack์€ ์™„์ „ํ•œ URL์„ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

Styles / Styles URL

๊ตฌ์„ฑ ์š”์†Œ์˜ ์Šคํƒ€์ผ์„ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์‹ค์ œ๋กœ ๋ถ„๋ฆฌ ๋œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๊ณ„ํšํ•˜๋Š” ๊ฒฝ์šฐ ํŠนํžˆ ์œ ์šฉํ•˜๋‹ค. styles ๋˜๋Š” styleUrl์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

์•„๋ž˜์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด styles ์†์„ฑ์€ CSS ๊ทœ์น™์˜ ๋ฐฐ์—ด์„ ๋ฌธ์ž์—ด๋กœ ์ทจํ•œ๋‹ค. ๊ฝค ๋นจ๋ฆฌ ์ž๋ž„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ณ„๋„์˜ ํŒŒ์ผ๊ณผ styleUrl์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ํ›„์ž์˜ ์ด๋ฆ„์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด URL ๋ฐฐ์—ด์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

@Component({
  selector: 'ns-styled-pony',
  template: '<div class="pony">{{pony.name}}</div>',
  styles: ['.pony{ color: red; }']
})
export class StyledPonyComponent {
  @Input() pony: any;
}

Declarations

@NgModule์˜ ์„ ์–ธ์—์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๋ชจ๋“  ์ง€์‹œ๋ฌธ๊ณผ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์„ ์–ธํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•ด๋ผ. ๊ทธ๋ ‡๊ฒŒ ํ•˜์ง€ ์•Š์œผ๋ฉด ํ…œํ”Œ๋ฆฟ์—์„œ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์„ ํƒ ๋˜์ง€ ์•Š์œผ๋ฉฐ ์ด์œ ๋ฅผ ํŒŒ์•…ํ•˜๋Š” ๋ฐ ๋งŽ์€ ์‹œ๊ฐ„์„ ๋‚ญ๋น„ ํ•œ๋‹ค.

๋‘ ๊ฐ€์ง€ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ์‹ค์ˆ˜๋Š” ์ง€์‹œ๋ฌธ์„ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด ๋ฒ„๋ฆฌ๊ณ  ์ž˜๋ชป๋œ ์„ ํƒ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์™œ ์•„๋ฌด ์ผ๋„ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ์ด๊ฒƒ๋“ค์„ ์ฃผ์˜ํ•˜๋„๋ก ํ•ด๋ผ!! ์šฐ๋ฆฌ๋Š” ์ฟผ๋ฆฌ, ๋ณ€๊ฒฝ ๊ฐ์ง€, ๋‚ด๋ณด๋‚ด๊ธฐ, ์บก์Šํ™” ์˜ต์…˜ ๋“ฑ๊ณผ ๊ฐ™์€ ๋ช‡ ๊ฐ€์ง€ ์‚ฌํ•ญ์„ ๋‚จ๊ฒจ ๋‘์—ˆ๋‹ค. ๊ณ ๊ธ‰ ์˜ต์…˜์ด๋ฏ€๋กœ ์ฆ‰์‹œ ํ•„์š”ํ•˜์ง€ ์•Š์ง€๋งŒ ์šฐ๋ฆฌ๋Š” ๊ณง ๊ณ ๊ธ‰ ์žฅ์—์„œ ๊ทธ๋“ค์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค!

Reference URL

Last updated