--이전중입니다--/비공개글

튜토리얼3

heestory 2016. 7. 15. 13:52

winstorm을 위한 어플리캐이션이 완성 되었다면

다른 여러 히어로들의 목록을 출력해 주는 것이 필요하다.


일단, 여러 히어로들에 대한 목록을 설정해 놓아야 한다.

app 폴더 내의 app.component.ts 파일의 Hero 클래스 선언 아래에 객체들의 배열을 사용하여 HEROES를 만든다.


1
2
3
4
5
6
7
8
9
10
11
12
const HEROES : Hero[] = [
    { 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' }
];
cs

HEROES는 Hero클래스의 배열에 해당하고

각각의 Hero 들에 id 와 name을 갖고 있는 값들이 들어간다.


이 배열들이 web에 바로 반영이 되어야 하지만 일단 가짜 값을 출력하도록 해보겠다.


AppConponent항복에 hero들을 출력하기 위해 heroes라는 변수를 만든다.


1
2
3
4
5
6
// .....
 
export class AppComponent {
    title = 'tour of heroes';
    public heroes = HEROES;
}
cs


이제 AppComponent가 heroes에 대한 값을 갖고 있기 때문에 이 값들을 채워주면 된다.


리스트를 출력할 때에는 ul 태그 혹은 ol 태그를 쓰는데 ol은 숫자로 순서가 표시되는 목록이다.

각각 목록의 값은 li태그에 나타낸다.



1
2
3
4
5
6
7
8
9
10
11
12
// .....
 
@Component({
    selector: 'my-app',
    template'<h1>{{title}}</h1>' +
              '<h2>My Heroes</h2>' +
              '<ul class = "heroes">' +
                 '<li>each hero\'s information</li>' +
              '</ul>'
})
 
// .....
cs




li태그를 여러번 반복하면 목록을 출력할 수 있다.

우리는 반복되는 값을 사용할 것이기 때문에 li태그 안에 ng속성을 이용한다.


별표시 ( asterisk , * ) 접두사는 li요소와 이것의 자식이 master template를 구성한다는 것을 말한다. ( ? ) 


heroes배열 안의 hero들을 반복해 달라는 의미로 let hero of heroes를 사용한다. 


정확한 의미는 heroes배열 안의 각각의 hero들을 취하며 로컬 hero 변수에 이것을 저장하고

템플릿객체에 해당하는 것을 사용할 수 있게 하라. 라는 의미라는데 이것은 잘 이해되지 않는다.


let 키워드를 hero 앞에 사용하게 되면서 우리가 변수값으로 사용하려는 값이 hero임을 알게 한다.


1
2
3
4
5
6
7
8
9
10
11
12
// .....
 
@Component({
    selector: 'my-app',
    template'<h1>{{title}}</h1>' +
              '<h2>My Heroes</h2>' +
              '<ul class = "heroes">' +
                 '<li *ngFor="let hero of heroes">' +
              '</ul>'
})
 
// .....
cs


이제 li를 만드는 것 뿐만이 아니고 li에 해당하는 값을 넣어준다.

한 줄에 두가지 값이 들어가기 위해 span태그를 사용하여 구역을 나눠 값을 출력해 준다.


조금 더 디자인스러운 어플리케이션을 위해 style을 추가해 준다.

우리가 어플리캐이션을 구동하는데 필요한 속성이 @Component안에 있기 때문에 

CSS코드 또한 @Component안에 작성한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// .....
 
@Component({
    selector: 'my-app',
    template'<h1>{{title}}</h1>' +
              '<h2>My Heroes</h2>' +
              '<ul class = "heroes">' +
                 '<li *ngFor="let hero of heroes">' +
                     '<span class = "badge">{{hero.id}}</span> {{hero.name}}' +
                 '</li>' +
              '</ul>',
    styles: [`
      .selected {
        background-color: #CFD8DC !important;
        color: white;
      }
      .heroes {
        margin: 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.7em;
        background-color: #607D8B;
        line-height: 1em;
        position: relative;
        left: -1px;
        top: -4px;
        height: 1.8em;
        margin-right: .8em;
        border-radius: 4px 4px;
      }
    `]
})
 
// .....
cs



목록이 너무 길기 때문에 배열을 조금 줄이도록 하겠다.


hero목록으로 각각의 hero들을 어플리케이션에 출력했다.

이제 원하는 hero를 클릭하면 각각의 hero에 대한 상세한 내용이 출력되기를 뭔한다.


hero 목록인 master와 각각의 선택된 hero에 대한 delail을 보여주어야 한다.

이러한 패턴은 "master-detail"이라 불리는 패턴이다.


master와 detail을 연결하기 위해 클릭이벤트에 묶인 selectedHero라는 요소속성 (component property)를 이용한다.


1
2
3
4
5
6
7
8
9
10
11
12
// .....
@Component({
    selector: 'my-app',
    template'<h1>{{title}}</h1>' +
              '<h2>My Heroes</h2>' +
              '<ul class = "heroes">' +
                 '<li *ngFor="let hero of heroes" (click) = "onSelect(hero)">' +
                     '<span class = "badge">{{hero.id}}</span> {{hero.name}}' +
                 '</li>' +
              '</ul>',
    styles: 
// .....
cs


onSelect 메소드를 사용했지만 아직 정의하지 않았기 때문에

일단 selectedHero라는 속성을 AppComponent에 추가하고

아무것도 클릭하기 전에는 아무 hero도 선택되어 있지 않기 때문에 초기값을 지정할 필요가 없다.


onSelect 메소드를 추가해서 selectedHero 속성이 사용자가 클릭한 hero가 되도록 한다.


1
2
3
4
5
6
7
8
// .....
 
export class AppComponent {
    title = 'tour of heroes';
    public heroes = HEROES;
    selectedHero : Hero;
    onSelect(hero : Hero) {this.selectedHero = hero; }
}
cs


detail내용을 추가하기 위해서 html 태그를 추가한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// .....
 
@Component({
    selector: 'my-app',
    template'<h1>{{title}}</h1>' +
              '<h2>My Heroes</h2>' +
              '<ul class = "heroes">' +
                 '<li *ngFor="let hero of heroes" (click) = "onSelect(hero)">' +
                     '<span class = "badge">{{hero.id}}</span> {{hero.name}}' +
                 '</li>' +
              '</ul>' +
              '<h2>{{selectedHero.name}} details!</h2>' +
              '<div><label>id: </label>{{selectedHero.id}}</div>' +
              '<div>' +
                 '<label>name: </label>' +
                 '<input [(ngModel)]="selectedHero.name" placeholder="name"/> ' +
              '</div>',
    styles:
 
// .....
cs


하지만 실행 화면을 보면 방금 전까지 잘 나오던 값이 나오지 않는다. 


selectedHero가 아직 정의되어있지 않아 selectedHero.name이 없기 때문에

데이터를 제대로 불러오지 못하기 때문이다.


그래서 selectedHero가 없다면 detail내역이 출력되지 않게 하디 위해 ngIf를 사용한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// .....
 
    template'<h1>{{title}}</h1>' +
              '<h2>My Heroes</h2>' +
              '<ul class = "heroes">' +
                 '<li *ngFor="let hero of heroes" (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>',
 
// .....
cs



selectedHero가 없을 때, ngIf는 html문서에서 hero의 상세에 해당하는 div부분을 삭제한다.


사용자가 hero를 클릭할 때가 되어서야 selectedHero 가 존재하기 때문에 

ngIf가 hero의 세부사항을 제대로 가져올 수 있다.


선택된 hero가 리스트에서 볼 때에도 선택되었다는 것을 알아볼 수 있도록 선택된 항목에 대한 스타일을 추가한다.


만약 해당 아이템이 selectedHero 라면 true 값을 반환하여

CSS파일에 추가해 놓은 selected 클래스가 활성화되게 한다.


반대로, 해당 아이템이 selectedHero가 아니면 false값을 반환하여 selected 클래스를 비활성화한다.


1
2
3
4
5
6
7
8
9
// .....
              '<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>' +
// .....
cs





(( app/app.component.ts 전체코드)) 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import { Component } from '@angular/core';
 
export class Hero {
    id : number;
    name : string;
}
 
const HEROES : Hero[] = [
    { id: 11, name: 'Mr. Nice' },
    { id: 12, name: 'Narco' },
    { id: 13, name: 'Bombasto' }
];
 
@Component({
    selector: 'my-app',
    template'<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: [`
      .selected {
        background-color: #CFD8DC !important;
        color: white;
      }
      .heroes {
        margin: 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.7em;
        background-color: #607D8B;
        line-height: 1em;
        position: relative;
        left: -1px;
        top: -4px;
        height: 1.8em;
        margin-right: .8em;
        border-radius: 4px 4px;
      }
    `]
})
 
 
export class AppComponent {
    title = 'tour of heroes';
    public heroes = HEROES;
    selectedHero : Hero;
    onSelect(hero : Hero) {this.selectedHero = hero; }
}
cs


원문 출처 : https://angular.io/docs/ts/latest/tutorial/toh-pt2.html