반응형

주 / 상세 콤포넌트

현재  HeroesComponent 영웅들의 목록과 선택된 영웅의 상세 정보 둘다 표시된다

하나의 컴포넌트 안에 모든 특징을 보유한는것은  큰 애플리케이션을 유지 할수 없다. 각각 특정 작업 혹은 작업흐름 집중할수 있도록, 큰 컴포넌트를 더 작은 서브 컴포넌트로 분리하길 원한다. 

이페이지에서 재사용가능한  HeroDetailsComponent를 분리하는 방량의  첫번째 단계를 할수 있다.

HeroesComponent는 영웅들 목록에 있는 영웅들을 단지 내놓기만한다. HeroDetailsComponent 선택된 영웅의 상세를 내놓는다.


HeroDetailComponent 제작

Angular CLI를 사용해서 hero-detail 이름으로 새로운 컴포넌트를 자동생성한다.

ng generate component hero-detail

그 명령은 HeroDetailComponent 파일들과 AppModule에서 컴포넌트를 선언하는 것으로 골격을 이룬다.

PS D:\workspace\dev\angular02\angular-tour-of-heroes> ng generate component hero-detail

  create src/app/hero-detail/hero-detail.component.html (33 bytes)

  create src/app/hero-detail/hero-detail.component.spec.ts (660 bytes)

  create src/app/hero-detail/hero-detail.component.ts (297 bytes)

  create src/app/hero-detail/hero-detail.component.css (0 bytes)

  update src/app/app.module.ts (592 bytes)

실행된 내용이다. 관련 컴포넌트 이름으로 파일 4개를 만들고 app.module.ts 파일을 업데이트 했다.


템플릿 작성

영웅 상세 HTML을 HeroesComponent 템플릿 아래에서 자르고  HeroDetailComponent 템플릿의  그 생성된 표준문안 위에 붙혀넣는다. 

붙혀넣은 HTML은 selectedHero을 참조한다. 새로운 HeroDetailComponent   꼭 선택된 영웅 뿐만아니라 현재의 어떤 영웅을 줄 수 있다.  따라서  템플릿 안의 모든 "hero"를 "selectedHero"로  교체한다.

완료되면 HeroDetailComponent 템플릿 다음 처럼 보여야 한다.

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>


영웅 속성에 @Input() 추가

HeroDetailComponent 템플릿은 콤포넌트에 Hero 유형의 영웅 속성에 바인드 된다.

HeroDetailComponent 클래스 파일을 열고  Hero symbol을 추가한다.

src/app/hero-detail/hero-detail.component.ts (import Hero)

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

영웅 속성은 Input 속성 @Input() 데코레이터로 애토테이트된 것이어야 야한다.  외부 HeroesComponent 다음과 같이 바인드 하기 때문이다.

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

@angular/core import 문장을 Input을 추가하여  개정한다.

src/app/hero-detail/hero-detail.component.ts (import Input)

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

@Input() 데코레이를 영웅 속성 앞에 추가합니다.

@Input() hero: Hero;

저것은 만들고 싶은 HeroDetailComponent 클래스에 대해 변경해야할 유일한 변경사항입니다. 더이상 속성들이 없다. 프리젠테이션 로직이 아니다.

그 컴포넌트는 단순히 영웅 속성을 통해 영웅 개체를 수신하고 표시한다.


HeroDetailComponent를 보여주자.

HeroesComponent는 여진히  주/상세가 아닙니다.

그것의 자신을 영웅 상세를 표시하고, 템플릿의 일부를 자르기 전에것을 사용한다. 지금 이것은 HeroDetailComponent로 위임 할수 있다.

두개의 콤포넌트들은 부모/자식 관계를 가질수 있다.

그 부모 HeroesComponent 는  자식 HeroDetailComponent 를 보여주기 위해  보내진 새로운 영웅 사용자가 목록에서 영웅을 선택할때마다  제어 할것이다. 

HeroesComponent 클래스가 변하는것을 원치 않지만 그것의 템플릿을 변경 할 것이다.


HeroesComponent 템플릿 업데이트

HeroDetailComponent 선택자는 'app-hero-detail' 이다.

<app-hero-detail> 요소를 HeroesComponent 템플릿의 아래 부근에 추가하고 그곳에서 영웅 상세가  예전처럼 보여진다.

HeroesComponent.selectedHero 영우 속성의 요소로 바인드한다.


heroes.component.html (HeroDetail binding)

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

[hero]="selectedHero" 은 앵귤라 속성을 바인딩하는 것이다.

이것은  selectedHero 에서  단방향 데이터 방인딩이다.

이제 사용자가 목록의 영웅을 클릭하면 selectedHero 변한다. 

selectedHero 변할때, 영웅이 속성 바인딩 업데이트 되고 HeroDetailComponent 그 새로운 영웅을 표시한다.

변경한 HeroesComponent 템플릿은 다음처럼 보인다.

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>

브라우저가 재생되고 앱 작업이 이전과 같이 재식작  된다 .


뭐가 바뀌었나?

앞에서와 같이, 매번 사용자가 영웅 이름을 클릭 할때마다, 그 영운 상세는 영웅 목록 아래로 나타난다. 지금 HeroDetailComponent는 HeroesComponent 대신에  그것들이 상세에 있는 것이다.

원래 HeroesComponent를 두개의 콤포넌트로 리팩토링하면 현재와 미래 모두 유익한 효과를 얻을수 있다.

HeroesComponent는 책임을 줄임으로서 간소화 했다.

부모 HeroesComponent의 간섭 없이 풍부한 영웅 수정자안에서 HeroDetailComponent를 진화 할수 있다.

영웅 상세 뷰의 간섭 없이  HeroesComponent는 진화 할수 있다.

어떤 미래 콤포넌트의 템플릿에서 HeroDetailComponent를 재사용 할수 있다.


마지막 코드 리뷰

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() {

  }

}


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>


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>


요약

별도의 재사용 할수 있는 HeroDetailComponent를  생성된다.

부모 HeroesComponent는 자식 HeroDetailComponent에 대한 통제를 준는것을 속성바인딩을 사용한다.

@Input 데코레이터는 확장 HeroesComponent으로 빌등 가능한 영웅 속성을  만들때 사용한다.



반응형

+ Recent posts