Tour of Heroes - 마스터-디테일 Components (@Input)

소스코드

이 게시물에는 코드작성이 포함되어 있습니다. 소스코드를 받으신 후 진행해 주세요. MEAN Stack/개발 환경 구축에서 설명된 프로그램들(git, npm, atom editor)이 있어야 아래의 명령어들을 실행할 수 있습니다.

이 게시물의 소스코드는 Tour of Heroes / Tour of Heroes - 리스트 표시하기 (*ngFor, *ngIf)에서 이어집니다.

tour-of-heroes.git 을 clone 한 적이 있는 경우: 터미널에서 해당 폴더로 이동 후 아래 명령어들을 붙여넣기합니다. 폴더 내 모든 코드가 이 게시물의 코드로 교체됩니다. 이를 원치 않으시면 이 방법을 선택하지 마세요.

git reset --hard
git pull
git reset --hard 2a17f91
git reset --soft ee73104
npm install
atom .

tour-of-heroes.git 을 clone 한 적이 없는 경우: 터미널에서 코드를 다운 받을 폴더로 이동한 후 아래 명령어들을 붙여넣기하여 tour-of-heroes.git 을 clone 합니다.

git clone https://github.com/a-mean-blogger/tour-of-heroes.git
cd tour-of-heroes
git reset --hard 2a17f91
git reset --soft ee73104
npm install
atom .

- Github에서 소스코드 보기: https://github.com/a-mean-blogger/tour-of-heroes/tree/2a17f9100620c938550d319efedd7b095ff6e1b5


현재 heroes component는 hero의 리스트를 보여주는 역할과 하나의 선택된 hero를 수정하는 역할 두가지를 하고 있습니다. 이번 강의를 통해 hero의 리스트 코드와 hero editor 코드를 각각의 component로 분리해 봅시다.

기존의 HeroesComponent는 hero의 리스트를 가지는 마스터(master) component가 되고, hero editor는HeroDetailComponent로 분리되어 디테일(detail) component가 됩니다.

또한 이번강의에서 마스터 component에서 디테일 component로 어떻게 데이터를 전달하는지 알아 봅시다.

폴더 구조

hero-detail component를 추가하기 위해 ng generate 명령어를 사용해야 하는데, 이번에는 아래처럼 축약형으로 사용해 봅시다.

$ ng g c hero-detail --skipTests

이처럼 ng generate 명령어는 ng g로, componentc로 축약해서 사용할 수 있습니다.

코드 - Hero Detail Component

// src/app/hero-detail/hero-detail.component.ts

import { Component, OnInit, Input } from '@angular/core';

import { Hero } from '../hero';

@Component({
  selector: 'app-hero-detail',
  templateUrl: './hero-detail.component.html',
  styleUrls: ['./hero-detail.component.css']
})
export class HeroDetailComponent implements OnInit {
  @Input() hero: Hero;

  constructor() { }

  ngOnInit() {
  }

}

기존에 hero editor 코드를 HeroDetailComponent로 분리했습니다. 이 component의 코드에서 특별한 부분은 @input()입니다. 우선 @가 붙어있는 것으로 봐서 decorator임을 알 수 있고, Hero 타입인 hero 항목에 붙어있는 것을 볼 수 있습니다.

@input() decorator는 해당 항목(property)의 값을 component selector 태그로 부터 받을 수 있게 해줍니다. Hero detail component의 selector는 'app-hero-detail'이므로 html 코드에서 <app-hero-detail></app-hero-detail>를 태그를 사용해서 hero detail component를 불러올 수 있습니다. 여기에 @input() hero에 의해 hero의 값을 태그로 부터 받을 수 있게 됩니다.

즉, <app-hero-detail [hero]=""></app-hero-detail>의 형태로 hero의 값을 상위 component로 부터 받아 올 수 있게 됩니다. 이부분은 heroes.component.html의 코드에서 다시 살펴보겠습니다.

<!-- src/app/hero-detail/hero-detail.component.html -->

<div *ngIf="hero">

  <h2>{{hero.name | uppercase}} Details</h2>
  <div><span>id: </span>{{hero.id}}</div>
  <div>
    <label>name:
      <input [(ngModel)]="hero.name" placeholder="name"/>
    </label>
  </div>

</div>

Hero editor 코드로, selectedHero가 hero로 바뀐 것 말고는 동일한 코드입니다. 이전 hero editor가 heroes component속의 코드에 종속되어 selectedHero를 보여주고 수정하는 역할이였다면, 이제는 @input() hero를 통해 component로 hero를 전달받고, 이 hero를 보여주고 수정하는 완전히 독립된 component가 되었습니다.

label {
  display: inline-block;
  width: 3em;
  margin: .5em 0;
  color: #607D8B;
  font-weight: bold;
}
input {
  height: 2em;
  font-size: 1em;
  padding-left: .4em;
}
button {
  margin-top: 20px;
  font-family: Arial;
  background-color: #eee;
  border: none;
  padding: 5px 10px;
  border-radius: 4px;
  cursor: pointer;
  cursor: hand;
}
button:hover {
  background-color: #cfd8dc;
}
button:disabled {
  background-color: #eee;
  color: #ccc;
  cursor: auto;
}

코드 - 그 외

<!-- src/app/heroes/heroes.component.html -->

<h2>My Heroes</h2>
<ul class="heroes">
  <li *ngFor="let hero of heroes"
    [class.selected]="hero === selectedHero"
    (click)="onSelect(hero)">
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>

<app-hero-detail [hero]="selectedHero"></app-hero-detail>

기존의 hero editor 코드가 사라지고 <app-hero-detail [hero]="selectedHero"></app-hero-detail>가 추가되었습니다.

*ngFor="let hero of heroes"를 통해 hero 리스트가 표시되고, (click)="onSelect(hero)"를 통해 클릭된 hero가 selectedHero에 대입되고, <app-hero-detail [hero]="selectedHero"></app-hero-detail>를 통해 HeroDetailComponenthero항목으로 전달되는 과정을 완벽하게 이해하셔야 합니다.

// src/app/app.module.ts

...
import { HeroesComponent } from './heroes/heroes.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component'; // 1

@NgModule({
  declarations: [
    AppComponent,
    HeroesComponent,
    HeroDetailComponent, // 1
  ],
  ...

app module에는 HeroDetailComponent가 declarations로 등록되었습니다.

마치며..

이번 강의에서는 @Input decorator를 통해 하위 component로 데이터를 전달하는 방법에 대해 알아봤습니다.

하나의 component를 두개로 나누어서 코드를 내부적으로 정리하는 과정이며 사이트 자체의 변화는 없습니다.

댓글

댓글쓰기

이 글에 댓글을 다시려면 SNS 계정으로 로그인하세요. 자세히 알아보기

UP