Skip to content

3. 사용해보기: 네비게이션


이 문서는 사용해보기 튜토리얼의 첫 번째 단계에서 만든 앱을 기준으로 한다.


지금까지 작업한 앱에는 상품 목록 화면과 상품 상세정보 화면이 존재한다.


이 애플리케이션에 이런 기능을 추가해 보자:


  • 브라우저 주소 표시줄에 URL을 입력하면 해당 제품 화면으로 이동한다.
  • 싱글 페이지 애플리케이션에서 링크를 클릭하면 화면을 전환한다.
  • 브라우저의 "뒤로 가기", "앞으로 가기" 버튼을 누르면 브라우저 히스토리를 기반으로 이동한다.


1. URL 경로와 컴포넌트 연결하기

이 애플리케이션에는 이미 Angular Router를 사용해서 ProductListComponent로 화면을 전환하는 기능이 추가되어 있다. 이번 섹션에서는 상품의 상세정보 화면으로 이동하는 라우팅 규칙을 추가해 보자.


상품의 상세정보를 표시하는 컴포넌트를 생성한다. 파일 목록에서 app 폴더에 마우스 오른쪽 버튼을 클릭하고 Angular Generator를 선택한 후에 Component를 선택하면 된다. 이 때 컴포넌트의 이름은 product-details라고 지정한다.


app.module.ts 파일을 열고 상품 상세정보에 해당하는 라우팅 규칙을 추가한다. pathproducts/:productId를 지정하고 componentProductDetailsComponent를 지정하면 된다.


src/app/app.module.ts
@NgModule({
  imports: [
    BrowserModule,
    ReactiveFormsModule,
    RouterModule.forRoot([
      { path: '', component: ProductListComponent },
      { path: 'products/:productId', component: ProductDetailsComponent },
    ])
  ],
  declarations: [
    AppComponent,
    TopBarComponent,
    ProductListComponent,
    ProductAlertsComponent,
    ProductDetailsComponent,
  ],


product-list.component.html 파일을 연다.


상품 이름을 표시하는 <a> 링크에 routerLink를 추가하고 인자로 product.id를 지정한다.


src/app/product-list/product-list.component.html
<div *ngFor="let product of products">
  <h3>
    <a
      [title]="product.name + ' details'"
      [routerLink]="['/products', product.id]"
    >
      {{ product.name }}
    </a>
  </h3>

  <!-- . . . -->
</div>


RouterLink 디렉티브를 활용하면 <a> 엘리먼트를 커스터마이징할 수 있다. 이 경우에 라우팅 경로는 /products라는 URL 세그먼트로 시작된다. 그리고 마지막 세그먼트는 해당 상품의 id 프로퍼티 값이 할당된다. 그래서 상품의 id 값이 1인 경우라면 최종 URL은 https://getting-started-myfork.stackblitz.io/products/1과 같은 형태가 된다.


상품의 이름을 클릭했을 때 라우터가 제대로 동작하는지 확인해 보자. 그러면 ProductDetailsComponent로 전환되면서 "product-details works!"라는 문구가 화면에 표시된다. 미리보기 화면의 URL도 변경된 것을 확인해 보자. products/#라는 주소의 마지막 세그먼트 #는 이전에 클릭한 상품의 id 값이 된다.


001


2. 상품 상세정보 표시하기

ProductDetailsComponent는 개별 상품의 정보를 표시한다. 그리고 Angular Router는 사전에 정의된 라우팅 규칙 중에서 현재 브라우저의 URL에 매칭되는 컴포넌트를 화면에 표시한다.


이번 섹션에서는 products 데이터와 라우팅 규칙을 결합해서 특정 상품의 상세정보를 화면에 표시해 보자.


product-details.component.ts 파일에 @angular/router 패키지로 제공되는 ActivatedRoute..products 파일로 준비된 products 배열을 불러온다.


src/app/product-details/product-details.component.ts
import { Component, OnInit } from "@angular/core";
import { ActivatedRoute } from "@angular/router";

import { Product, products } from "../products";


product 프로퍼티를 정의한다.


src/app/product-details/product-details.component.ts
export class ProductDetailsComponent implements OnInit {
  product: Product | undefined;
  /* ... */
}


생성자 소괄호 안에 private route: ActivatedRoute를 추가해서 ActivatedRouteconstructor() 안에 의존성으로 주입한다.


src/app/product-details/product-details.component.ts
export class ProductDetailsComponent implements OnInit {
  product: Product | undefined;

  constructor(private route: ActivatedRoute) {}
}


ActivatedRoute는 Angular Router가 로드한 개별 컴포넌트에 대한 정보를 담고 있다. 이 객체를 참조하면 해당 컴포넌트가 표시될 때 사용된 라우팅 규칙이나 라우팅 인자를 확인할 수 있다. ActivatedRoute를 의존성으로 주입하면 이제 컴포넌트에서 이 서비스를 사용할 준비는 끝났다.


Note


ngOnInit() 메서드 안에서 라우팅 인자로 전달된 productId를 참조하고, 이 값에 해당되는 상품을 products 배열 안에서 찾는다.


src/app/product-details/product-details.component.ts
ngOnInit() {
  // First get the product id from the current route.
  const routeParams = this.route.snapshot.paramMap;
  const productIdFromRoute = Number(routeParams.get('productId'));

  // Find the product that correspond with the id provided in route.
  this.product = products.find(product => product.id === productIdFromRoute);
}


경로 매개변수는 경로에 정의한 경로 변수에 해당한다. 경로 매개변수에 액세스하기 위해 특정 시점의 활성 경로에 대한 정보가 포함된 ActivatedRouteSnapshotroute.snapshot을 사용한다. 경로와 일치하는 URL은 productId를 제공하기 때문에 Angular는 productId를 사용하여 각 고유 상품에 대한 상세정보를 표시한다.


상품의 상세정보를 표시할 수 있도록 ProductDetailsComponent 템플릿을 수정하는데, 이 때 *ngIf를 사용한다. 이렇게 작성하면 해당 상품이 존재할 때만 <div> 엘리먼트가 렌더링되면서 상품의 이름, 가격, 설명이 화면에 표시된다.


src/app/product-details/product-details.component.html
<h2>Product Details</h2>

<div *ngIf="product">
  <h3>{{ product.name }}</h3>
  <h4>{{ product.price | currency }}</h4>
  <p>{{ product.description }}</p>
</div>


<h4>{{ product.price | currency }}</h4> 코드를 보면 product.price는 숫자 타입이지만 금액 형식으로 표시하기 위해 currency 파이프를 사용했다. 파이프는 HTML 템플릿에 표시되는 데이터의 형식을 조작할 때 사용한다.


Note

  • Angular 파이프에 대해 자세하게 알아보려면 파이프 문서를 참고한다.


이제 사용자가 상품 목록에서 상품의 이름을 클릭하면 라우터가 해당 상품에 해당하는 URL로 이동하면서 ProductDetailsComponent가 화면에 표시되고, 상품의 상세정보가 화면에 표시된다.


002


Note


References