Tour of Heroes - 리스트 표시하기 (*ngFor, *ngIf)

소스코드

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

이 게시물의 소스코드는 Tour of Heroes / Tour of Heroes - Hero 에디터 폼(form) (NgModel, Angular Pipe)에서 이어집니다.

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

git reset --hard
git pull
git reset --hard ee73104
git reset --soft 7eccad1
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 ee73104
git reset --soft 7eccad1
npm install
atom .

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


튜토리얼 사이트에 게시될 '영웅들'(heroes)의 목록을 mock data(임시로 사용하는 가짜 데이터) 배열로 만들고 이 영웅들의 목록을 웹사이트에 리스트로 나타내 봅시다.

폴더 구조

mock-heroes.ts 파일은 ng generate명령어로 만들 수 없고 직접 파일을 생성해야 합니다.

코드 - mock-heroes.ts

// src/app/mock-heroes.ts

import { Hero } from './hero';

export const HEROES: Hero[] = [
  { id: 11, name: 'Dr 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' }
];

이 사이트가 실전 사이트라면 당연히 DB를 연결하여 hero data를 저장하고 불러오겠지만, Tour of Heroes 튜토리얼의 목적은 Angular의 기초를 익히는 것이기 때문에 DB를 사용하지 않고 위와 같이 임시 데이터(mock data)를 만들어서 사용합니다.

const 키워드를 사용해서 HEROS라는 상수(constant)를 선언합니다. 이 HEROES 상수의 타입은 Hero class의 배열인 Hero[]입니다. 이처럼 []을 타입 뒤에 넣으면, '해당 타입의 배열' 타입을 타나냅니다.

이 상수 앞에 export 키워드를 붙여서 다른 파일에서 이 상수를 사용할 수 있게 하였습니다. 이전 강의에서는 Hero class에 export 키워드를 붙였었는데요, 이처럼 어떠한 객체라도 export 키워드를 사용할 수 있으며, export된 객체는 다른 파일에서 import로 불러올 수 있습니다.

코드 - Heroes Component

// src/app/heroes/heroes.component.ts

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

import { Hero } from '../hero';
import { HEROES } from '../mock-heroes'; // 1

...
export class HeroesComponent implements OnInit {
  heroes = HEROES; // 1
  selectedHero: Hero; // 2

  constructor() { }

  ngOnInit() {
  }

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

이전 강의의 코드와 비교해서 변화가 없는 부분은 "..."로 생략하였습니다.

1. Heroes component에는 원래있던 hero 항목(property) 지우고 HEROES 상수를 가져와서 heroes 항목으로 추가하였습니다. hero 변수의 이름은 영어 단수형으로 hero 한명의 데이터를 담고 있었는데, 이제 배열인 HEROES가 담기게 되니 heroes라는 복수형이 되었습니다.

2. selectedHero라는 항목도 추가되었는데, 이용자가 heroes 배열에서 하나의 hero를 클릭하면, 클릭된 heroselectedHero에 담기게 됩니다. 이전 강의에서 만든 hero editor form 역시 이제 selectedHero를 대상으로 작동합니다. 이 부분은 view 코드에서 자세히 살펴봅시다.

3. onSelect함수는 view 코드에서 이용자가 영웅을 클릭하면 호출될 함수입니다. 처음으로 TypeScript의 함수를 만들었는데, 형태를 살펴봅시다.

TypeScript의 함수에는 :를 사용해서 인자(parameter)에 타입을 줄 수 있고, 함수 자체에도 return 타입을 추가할 수 있습니다. onSelect함수는 Hero타입인 hero인자를 하나 가지고 있고, 함수의 return 타입은 void입니다. void는 함수가 어떠한 값도 return하지 않는다는 의미입니다. 함수의 인자 타입이나 함수의 return타입은 선택사항이며 이들을 제외해버리면 JavaScript의 함수와 100% 호환이 되는 형태입니다.

onSelect함수는 hero인자를 selectdHero에 대입하는 일을 합니다. onSelect함수가 HeroesCompoent class의 항목이고, selectdHero 역시 동일한 class의 항목이므로, onSelect함수안에서 자신의 class의 selectdHero 항목에 접근하기 위해 this.selectedHero를 사용했습니다. this는 자기 자신 class의 항목을 사용할 때 항목 이름 앞에 붙이는 것을 알아 둡시다.

<!-- 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>

<div *ngIf="selectedHero">

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

</div>

1. *ngFor를 사용해서 heroes 배열을 li 태그로 반복합니다. *ngFor는 *ngFor="let 반복에_사용될_변수명 of 배열"의 형태로 사용합니다heroes 배열 속의 데이터를 순서대로 하나씩 꺼내면서 해당 데이터를 hero변수에 대입한 후 li 태그와 그 안의 코드들을 만들게 됩니다. 이때 li 태그 안의 코드에서는 hero변수를 통해 heroes배열의 해당 데이터를 사용할 수 있습니다.

2. [class.selected]="hero === selectedHero"는 li 태그에 'selected'라는 css 클라스를 hero === selectedHero인 경우에만 추가하는 코드입니다. [class.클라스_이름]="조건"의 형태로 css 클라스를 해당 태그에 dynamic하게 추가할 수 있습니다. 현재 *ngFor 통해 반복중인 hero변수가 selectedHero인 경우에만 'selected' 클라스를 li 태그에 추가합니다.

3. (click)="onSelect(hero)"은 현재 해당 태그(현재 li 태그)에 click 이벤트가 오는 경우 onSelect함수에 *ngFor 통해 반복중인 hero변수를 인자로 넣어서 호출하는 코드입니다. 이처럼 (이벤트_이름)="함수_이름()"를 사용해서 html 이벤트가 발생할 시 호출할 component의 함수를 지정할 수 있습니다. 사용할 수 있는 이벤트의 목록은 https://www.w3schools.com/jsref/dom_obj_event.asp 등 인터넷 검색을 통해 찾을 수 있습니다.

4. *ngIf는 해당 태그(현재 div 태그)를 render할지 하지 않을지를 결정합니다. *ngIf="조건"의 형태로 조건이 참인 경우에만 해당 태그를 render합니다. 현재 조건은 selectedHero으로 selectedHero의 값이 존재하는 경우에만 이전강의에서 만든 hero editor form을 render합니다.

(), [], [()], * 에 대해 확실히 이해하고 넘어갑시다.

  • Angular view에서 *ngIf, *ngfor와 같이 *로 시작하는 명령어는 html 구조를 변경하는데 사용되는 명령어입니다.
  • Angular view에서 [태그_항목]는 해당 태그_항목에 값을 전달할 때 쓰입니다.
  • Angular view에서 (이벤트)는 해당 태그에서 발생하는 이벤트를 처리하기 위해 쓰입니다.
  • [(ngModel)]은 양방향으로 값을 주고 받으므로 ( )[ ] 모두 쓰인 형태입니다.
  • (), [], [()], *다음에 오는 =""안에는 typeScript 코드가 들어갑니다.

실행 결과

사이트에 접속하면 위와 같이 mock data의 hero들이 나열되어 보여집니다. 하나를 클릭해 봅시다.

이전 강의에서 만들었던 hero editor가 밑에 나타나며 이전강의와 마찬가지로 작동합니다.

마치며..

이번 강의에서는

  • :타입_or_클라스[]
  • TypeScript 함수의 인자에 타입을 주는법/return 타입 설정하는 법
  • this
  • *ngIf
  • *ngFor
  • [class.클라스_이름]
  • (이벤트)
  • ( ), [ ], [( )]의 차이점

에 대해 알아보았습니다. 위 개념들을 다른 사람에게 설명할 수 있을 정도로 이해할 수 있도록 합시다.

댓글

댓글쓰기

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

UP