Multiple Components(@input)

소스코드

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

이 게시물의 소스코드는 Tour of Heroes / MASTER/DETAIL(*ngFor, [class], (click), *ngIf)에서 이어집니다.

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

git reset --hard
git pull
git reset --hard 0977d7b
git reset --soft 23a8737
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 0977d7b
git reset --soft 23a8737
npm install
atom .

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


    Angular사이트의 공식 tutorial인 Tour of Heroes의 세번째 강의, Multiple Components입니다.

      공식 tutorial link : https://angular.io/docs/ts/latest/tutorial/toh-pt3.html
      온라인 예제 : https://angular.io/generated/live-examples/toh-pt3/eplnkr.html

      지금까지는 웹사이트의 모든 class들을 app.component.ts에서 작성하였는데, 파일들 관리를 쉽게 하기 위해서 이 class들을 각자의 파일로 분리해 봅시다. 또한 @input을 사용해 상위 component에서 component로 값을 전달하는 방법을 알아 봅시다.
      이전 포스팅과 비교해서 기능상의 차이는 없습니다.

      폴더구조


      HeroDetailComponent class 와 Hero class를 app.component.ts에서 분리하여 새로운 파일로 만들어진 모습입니다.

      코드

      새로 생성된 파일부터 살펴봅시다.

      // src/app/hero.ts
      
      export class Hero {
        id: number;
        name: string;
      }

      Hero class는 단순히 Hero의 타입을 담고 있는 class입니다. 이전과 비교해서 달라진 부분은 없습니다.export를 사용해서 다른 파일에서 불러오기(import)가 가능하다는 것만 보시고 다음 파일로 넘어갑시다.

      // src/app/hero-detail.component.ts
      
      import { Component, Input } from '@angular/core'; //3
      import { Hero } from './hero'; //1
      
      @Component({
        selector: 'hero-detail', //2-1
        template: ` //2-2
          <div *ngIf="hero">
            <h2>{{hero.name}} details!</h2>
            <div>
              <label>id: </label>{{hero.id}}
            </div>
            <div>
              <label>name: </label>
              <input [(ngModel)]="hero.name" placeholder="name"/>
            </div>
          </div>
        `
      })
      export class HeroDetailComponent {
        @Input() hero: Hero; //3
      }

      이전에 <div *ngIf="selectedHero"> 부분을 때어내서 새로운 component 를 만들었습니다. 우선 눈여겨 봐야할 부분은 이 파일의 이름인데, Angular의 파일명 작성 약속(convention)을 따른 것입니다. 파일명 작성 약속은 다음과 같습니다.

        • 대소문자 구별을 하는 서버와 그렇지 않은 서버에서 동일하게 작동하기 위해 파일명은 소문자로만 작성
        • 파일명은 class이름과 동일
        • class의 역할(여기서는 component)은 .으로 나타냄.
        • 그외 단어와 단어 사이에 -를 사용하여 구분

        위 규칙을 모두 따른 결과 hero-detail.component.ts라는 파일 이름이 나오게 된 것입니다.

        이제 코드를 살펴봅시다.

        1. Hero 타입을 사용하기 위해 hero.ts에서 Hero class를 호출하고 있습니다.

        2-1. selectorhero-detail가 사용되었으므로 <hero-detail></hero-detail>를 html에 삽입하면 이 component를 호출할 수 있다는 것을 알 수 있습니다.

        2-2. template에는 원래 있던 selectedHero가 사라지고 hero로 바뀐 것을 제외하면 변화된 부분은 없습니다.

        3. 오늘 강의의 가장 중요한 부분인 @input입니다. component간에 값을 전달할 수 있게 해주는 decorator인데요, input decorator(@input)가 붙은 class의 항목은 html에서 해당 component를 호출할때 값을 전달 받을 수 있습니다. <selector_이름 [input_항목_이름]=""></selector_이름>의 형태로 호출하면 input_항목_이름이 전달됩니다. 

        // src/app/app.component.ts
        
        import { Component } from '@angular/core';
        
        import { Hero } from './hero'; //1
        
        const HEROES: Hero[] = [
          //...
        ];
        
        
        @Component({
          selector: 'my-app',
          template: ` //2
            <h1>{{title}}</h1>
            <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>
            <hero-detail [hero]="selectedHero"></hero-detail>
          `,
          styles: [`
            //...
          `]
        })
        export class AppComponent {
          //...
        }

        // ... 로 표시된 부부은 전과 비교해서 변화가 없는 부분입니다.

        1. Hero 타입을 사용하기 위해 hero.ts에서 Hero class를 호출하고 있습니다.

          2. 이 template의 마지막 부분 <hero-detail [hero]="selectedHero"></hero-detail>을 살펴봅시다.
          hero-detail은 HeroDetailComponent의 selector입니다. 이를 사용해서 html에 HeroDetailComponent를 호출하고, HeroDetailComponent의 hero에 selectedHero를 전달하고 있습니다. 이처럼 값을 전달할때는 []를 사용합니다. 전달받은 selectedHero는 HeroDetailComponent에서 hero로 간주됩니다.

          마지막으로 app.module을 살펴봅시다.

          // src/app/app.module.ts
          
          import { NgModule }      from '@angular/core';
          import { BrowserModule } from '@angular/platform-browser';
          import { FormsModule }   from '@angular/forms';
          
          import { AppComponent }        from './app.component';
          import { HeroDetailComponent } from './hero-detail.component'; //1
          
          @NgModule({
            imports: [
              BrowserModule,
              FormsModule
            ],
            declarations: [
              AppComponent,
              HeroDetailComponent //1
            ],
            bootstrap: [ AppComponent ]
          })
          export class AppModule { }

          1. Angular의 모든 component들은 @NgModuledeclarations에 등록되어야 사용할 수 있습니다. HeroDetailComponent 역시 import되고 등록되어야만 html에서 selector(hero-detail)를 통해 호출될 수 있습니다. 참고로 hero.ts의 Hero 클라스는 component가 아니라 타입을 정의하고 있는 단순 class이기 때문에 등록될 필요가 없습니다.

          마치며..

          • component 파일을 생성하면 app.module.ts에 등록해야 합니다.
          • 하위 component에 값을 전달하려면 해당 component는 @input을 가진 항목을 가지고 있어야 하며, <selector_이름 [항목]=전달할_값></selector_이름> 로 값을 전달합니다.

          댓글

          하영아빠 2017.07.13
          감사합니다.
          파빌리온 2017.08.03
          설명 좋아요.
          댓글쓰기

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

          UP