MASTER/DETAIL(*ngFor, [class], (click), *ngIf)

소스코드

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

이 게시물의 소스코드는 Tour of Heroes / 소개 및 Hero Editor(@Component, @NgModule, [(ngModel)])에서 이어집니다.

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

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

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


위 방법으로 소스코드를 다운받으시고 Atom text editor로 프로젝트를 열면 아래와 같은 화면이 보이게 됩니다.


이전 포스트와 비교하여 변경된 부분은 주황색으로, 새로 생성된 부분은 초록색으로 표시됩니다. 강의를 읽으실때 이렇게 켜놓고 보시면 어떤 부분이 바뀌었는지 확인하기 편합니다.

이번 포스트는 Angular사이트의 공식 tutorial인 Tour of Heroes의 두번째 강의, Master/Detail입니다.

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

$ ng serve --open

다운 받은 소스코드를 실행하여 뭐가 달라졌나 봅시다.

사이트가 실행되면 hero의 리스트가 표시됩니다. 리스트중에 항목을 하나 클릭하면..

지난 포스트처럼 editor가 나오고 이름을 변경하면 전체 사이트에서 이름이 변경되게 됩니다.

코드

이번 강의의 핵심은 다음와 같습니다.

  1. 배열을 사이트에 반복해서 보여주는 방법(*ngFor)
  2. 조건부로 css class를 적용하는 방법([class.클라스_이름]="조건")
  3. click 이벤트로 component의 함수를 실행시키는 방법((click)="함수(파라메터들)")
  4. 조건부로 html 코드를 보여주는 방법(*ngIf="조건")

모두 template과 관련된 내용이네요.

이번 포스트에서는 app.component.ts 파일만 변경되었습니다(app.module.ts는 comment만 지워졌습니다). 코드가 길어서 보기 힘드시면 창을 두개 띄우시고 한쪽에는 코드를, 다른 한쪽에는 설명을 놓고 비교해 보시면 편합니다.

// src/app/app.component.ts

import { Component } from '@angular/core';
export class Hero {
  id: number;
  name: string;
}

const HEROES: Hero[] = [ //1
  { id: 11, name: 'Mr. Nice' },
  { id: 12, name: 'Narco' },
  { id: 13, name: 'Bombasto' },
  { id: 14, name: 'Celeritas' },
  { id: 15, name: 'Magneta' },
  { id: 16, name: 'RubberMan' },
  { id: 17, name: 'Dynama' },
  { id: 18, name: 'Dr IQ' },
  { id: 19, name: 'Magma' },
  { id: 20, name: 'Tornado' }
];

@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>
    <div *ngIf="selectedHero">
      <h2>{{selectedHero.name}} details!</h2>
      <div><label>id: </label>{{selectedHero.id}}</div>
      <div>
        <label>name: </label>
        <input [(ngModel)]="selectedHero.name" placeholder="name"/>
      </div>
    </div>
  `,
  styles: [` //3
    .selected {
      background-color: #CFD8DC !important;
      color: white;
    }
    .heroes {
      margin: 0 0 2em 0;
      list-style-type: none;
      padding: 0;
      width: 15em;
    }
    .heroes li {
      cursor: pointer;
      position: relative;
      left: 0;
      background-color: #EEE;
      margin: .5em;
      padding: .3em 0;
      height: 1.6em;
      border-radius: 4px;
    }
    .heroes li.selected:hover {
      background-color: #BBD8DC !important;
      color: white;
    }
    .heroes li:hover {
      color: #607D8B;
      background-color: #DDD;
      left: .1em;
    }
    .heroes .text {
      position: relative;
      top: -3px;
    }
    .heroes .badge {
      display: inline-block;
      font-size: small;
      color: white;
      padding: 0.8em 0.7em 0 0.7em;
      background-color: #607D8B;
      line-height: 1em;
      position: relative;
      left: -1px;
      top: -4px;
      height: 1.8em;
      margin-right: .8em;
      border-radius: 4px 0 0 4px;
    }
  `]
})
export class AppComponent {
  title = 'Tour of Heroes';
  heroes = HEROES; //4-1
  selectedHero: Hero; //4-2

  onSelect(hero: Hero): void { //4-3
    this.selectedHero = hero;
  }
}

1. 지난번에 만든 Hero class로 HEROES라는 상수를 선언하고 있습니다. 타입 뒤에 []를 붙이면 배열이 되는 것을 알 수 있습니다.

2. template 은 자세히 설명하기 위해 밑에서 다시 설명하겠습니다.

3. @Componentstyles 항목이 추가되고 css 코드가 문자열 array로 들어가 있습니다. 프로젝트폴더/src/styles.css와 다르게 이곳에 정의된 css는 해당 component의 template에만 영향을 주게 됩니다. css 설명은 생략합니다.

4-1. 1번의 HEROES 상수를 AppComponent class의 heroes 항목에 대입합니다.

4-2. selectedHero 항목은 Hero 타입으로 설정하고 값은 대입하지 않습니다.

4-3.  함수이름(파라메터들): 리턴형식 {함수내용}의 형식으로 class안에 함수를 선언할 수 있습니다. 즉 함수이름은 onSelect이고 파라메터로 Hero타입인 hero를 받으며, 이 함수는 값을 리턴하지 않습니다(void). 함수내용을 보면 hero를 받아 this.selectedHero에 대입하는 것을 알 수 있습니다. TypeScript에서 this는 class 자체를 나타냅니다. 

마지막으로 template를 꼼꼼히 살펴봅시다.

    <h1>{{title}}</h1>
    <h2>My Heroes</h2>
    <ul class="heroes">
      <li *ngFor="let hero of heroes" <!-- 2-1 -->
        [class.selected]="hero === selectedHero" <!-- 2-2 -->
        (click)="onSelect(hero)"> <!-- 2-3 -->
        <span class="badge">{{hero.id}}</span> {{hero.name}}
      </li>
    </ul>
    <div *ngIf="selectedHero"> <!-- 2-4 -->
      <h2>{{selectedHero.name}} details!</h2>
      <div><label>id: </label>{{selectedHero.id}}</div>
      <div>
        <label>name: </label>
        <input [(ngModel)]="selectedHero.name" placeholder="name"/>
      </div>
    </div>

2-1. *ngFor를 사용해서 heroes 배열을 li태그에 반복시키고 있는 모습입니다. *ngFor="let 반복에_사용될_변수명 of 배열"의 형태를 하고 있습니다. 즉 heroes 배열의 각각 값을 돌면서 해당 값을 hero에 대입한 후 li 태그를 반복해서 만드는 것이지요.

2-2. Angular2의 template에서 []는 해당 태그(여기서는 li)의 property의 값을 설정하는 역할을 합니다. [class.클라스_이름]="조건"조건이 참인 경우 class property에 클라스_이름을 적용시킵니다. 2-1과 연결해서 보면 heroes의 배열의 값을 돌면서 해당 값이 현재 selectedHero과 같은 경우에만 li에의 css class로 selected를 줍니다.

2-3 Angular2의 template에서 ()는 이벤트를 나타냅니다.(click)="onSelect(hero)" 은 해당 liclick이 되면 onSelect함수를 호출하며 hero를 파라메터로 전달합니다. 4-3번에서 정의된 onSelect함수는 Hero타입의 값을 받아서 selectedHero의 값을 변경하는 역할을 합니다.

2-4 *ngIf="조건"은 조건이 참인 경우 해당 html코드를 보여줍니다. 여기서 조건은 변수인 selectedHero인데, 자바스크립트와 동일하게null, 0, ""(빈문자열), undefinedNaNfalse가 아닌 경우는 모두 참입니다.

2번을 전체를 보면, 2-3에서 li가 클릭되면 selectedHero에 값이 들어가게 되고, 2-4의div가 보여지게 되는 것입니다. 이때 2-4안에는 selectedHero.name, selectedHero.id를 표시하게 되는데, selectedHero의 값이 변경되면 함께 변경되게 됩니다.

마치며..

이번 포스팅에 사용된 *ngFor[class.클라스_이름]="조건"(click)="함수(파라메터들)"*ngIf="조건") 들은 거의 대부분의 Angular 사이트 제작에 필수적으로 사용되는 것들이므로 반드시 완벽하게 익히고 넘어가시기 바랍니다. 이해가 잘 안되시면 댓글로 남겨주세요!

댓글

하영아빠 2017.07.12
정말 완벽한 설명 감사합니다.
I
Ian H 2017.07.12
@하영아빠,
격려의 말씀 감사합니다!
파빌리온 2017.08.03
좋은강의 감사드려요
I
Ian H 2017.08.03
@파빌리온,
감사합니다^^
e
euiryun 2018.08.29
잘보고있습니다 공식 tutorial link : https://angular.io/docs/ts/latest/tutorial/toh-pt2.html RESOURCE NOT FOUND 네요 ㅠㅠ
I
Ian H 2018.08.29
@euiryun,
안녕하세요! angular.io 의 주소들이 업데이트되었네요. 지금 보니까 코드도 새버전에 맞춰서 업데이트 된 것 같은데, 나중에 강의를 업데이트 해야 할 것 같습니다. github의 사이트는 작동하니까 위 강의로 공부하셔도 문제는 없습니다. https://angular.io/tutorial 에서 tour of heroes 최신 강의를 볼 수 있습니다.
댓글쓰기

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

UP