이번 실습에서는 앱에 상세 페이지를 연결하는 방법을 알아봅니다.
IMPORTANT: 라우팅 실습은 로컬 환경에서 진행하는 것을 권장합니다.
학습 목표
이번 실습을 마치면 애플리케이션에서 상세 페이지로 이동할 수 있습니다.
라우팅 파라미터 개념 살펴보기
각 주택에는 사용자가 상세 페이지로 이동했을 때 표시할 고유한 정보가 있습니다. 이 정보를 표시하려면 라우팅 파라미터를 사용해야 합니다.
라우팅 파라미터를 사용하면 URL 경로에 동적 정보를 포함할 수 있습니다. 사용자가 선택한 주택을 식별하기 위해 HousingLocationInfo 타입의 id 프로퍼티를 사용합니다.
-
routerLink로 동적 경로 이동하기실습 10에서
src/app/routes.ts에 두 번째 라우팅 규칙을 추가했습니다. 이 규칙에는 라우팅 파라미터id를 나타내는 특별한 경로 구간이 있습니다:'details/:id'여기서
:id는 동적 값이며 코드에서 어떤 경로를 요청하는지에 따라 달라집니다.src/app/housing-location/housing-location.ts의section엘리먼트에 링크 태그를 추가하고routerLink디렉티브를 지정하세요:housing-location.ts에 routerLink 디렉티브가 있는 링크 추가하기
import {Component, input} from '@angular/core'; import {HousingLocationInfo} from '../housinglocation'; import {RouterLink} from '@angular/router'; @Component({ selector: 'app-housing-location', imports: [RouterLink], template: ` <section class="listing"> <img class="listing-photo" [src]="housingLocation().photo" alt="Exterior photo of {{ housingLocation().name }}" crossorigin /> <h2 class="listing-heading">{{ housingLocation().name }}</h2> <p class="listing-location">{{ housingLocation().city }}, {{ housingLocation().state }}</p> <a [routerLink]="['/details', housingLocation().id]">Learn More</a> </section> `, styleUrls: ['./housing-location.css'], }) export class HousingLocation { housingLocation = input.required<HousingLocationInfo>(); }routerLink디렉티브를 사용하면 Angular 라우터가 애플리케이션에 동적 링크를 만들 수 있습니다.routerLink에 전달하는 배열은 경로의 고정된 부분과 동적 데이터, 두 항목으로 구성됩니다.템플릿에서
routerLink를 사용하려면 파일 수준에서@angular/router의RouterLink를 불러오고 컴포넌트의imports배열에도 추가하세요.이제 앱의 라우팅이 동작하는지 확인할 수 있습니다. 브라우저에서 홈 페이지를 새로고침하고 주택의 "Learn More" 버튼을 클릭하세요.
-
라우팅 파라미터 가져오기
이 단계에서는
Details에서 라우팅 파라미터를 읽습니다. 현재 앱에는details works!가 표시됩니다. 다음으로 라우팅 파라미터로 전달받은id값을 표시하도록 코드를 수정합니다.src/app/details/details.ts에서Details에 필요한 함수, 클래스, 서비스를 불러오도록 import 구문을 수정하세요:
파일 수준 import 수정하기
import {Component, inject} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {HousingService} from '../housing.service'; import {HousingLocationInfo} from '../housinglocation'; @Component({ selector: 'app-details', template: ` <article> <img class="listing-photo" [src]="housingLocation?.photo" alt="Exterior photo of {{ housingLocation?.name }}" crossorigin /> <section class="listing-description"> <h2 class="listing-heading">{{ housingLocation?.name }}</h2> <p class="listing-location">{{ housingLocation?.city }}, {{ housingLocation?.state }}</p> </section> <section class="listing-features"> <h2 class="section-heading">About this housing location</h2> <ul> <li>Units available: {{ housingLocation?.availableUnits }}</li> <li>Does this location have wifi: {{ housingLocation?.wifi }}</li> <li>Does this location have laundry: {{ housingLocation?.laundry }}</li> </ul> </section> </article> `, styleUrls: ['./details.css'], }) export class Details { route: ActivatedRoute = inject(ActivatedRoute); housingService = inject(HousingService); housingLocation: HousingLocationInfo | undefined; constructor() { const housingLocationId = Number(this.route.snapshot.params['id']); this.housingLocation = this.housingService.getHousingLocationById(housingLocationId); } }@Component데코레이터의template프로퍼티를 수정해housingLocationId값을 표시하세요:template: `<p>details works! {{ housingLocationId }}</p>`,Details클래스의 본문을 다음 코드로 수정하세요:export class Details { route: ActivatedRoute = inject(ActivatedRoute); housingLocationId = -1; constructor() { this.housingLocationId = Number(this.route.snapshot.params['id']); } }이 코드는
Details에서 현재 라우팅 정보를 제공하는ActivatedRoute를 사용하게 합니다.constructor에서는 라우팅 파라미터로 가져온id를 문자열에서 숫자로 변환합니다.모든 변경 사항을 저장하세요.
브라우저에서 주택의 "Learn More" 링크를 클릭하고 페이지의 숫자가 해당 주택 데이터의
id프로퍼티와 일치하는지 확인하세요.
-
Details수정하기이제 라우팅이 정상적으로 동작하므로
Details템플릿을 수정해 라우팅 파라미터에 해당하는 주택의 구체적인 정보를 표시합니다.데이터를 가져오기 위해
HousingService를 호출합니다.템플릿을 다음 코드와 같이 수정하세요:
src/app/details/details.ts의 Details 템플릿 수정하기
import {Component, inject} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {HousingService} from '../housing.service'; import {HousingLocationInfo} from '../housinglocation'; @Component({ selector: 'app-details', template: ` <article> <img class="listing-photo" [src]="housingLocation?.photo" alt="Exterior photo of {{ housingLocation?.name }}" crossorigin /> <section class="listing-description"> <h2 class="listing-heading">{{ housingLocation?.name }}</h2> <p class="listing-location">{{ housingLocation?.city }}, {{ housingLocation?.state }}</p> </section> <section class="listing-features"> <h2 class="section-heading">About this housing location</h2> <ul> <li>Units available: {{ housingLocation?.availableUnits }}</li> <li>Does this location have wifi: {{ housingLocation?.wifi }}</li> <li>Does this location have laundry: {{ housingLocation?.laundry }}</li> </ul> </section> </article> `, styleUrls: ['./details.css'], }) export class Details { route: ActivatedRoute = inject(ActivatedRoute); housingService = inject(HousingService); housingLocation: HousingLocationInfo | undefined; constructor() { const housingLocationId = Number(this.route.snapshot.params['id']); this.housingLocation = this.housingService.getHousingLocationById(housingLocationId); } }housingLocation의 프로퍼티에 옵셔널 체이닝 연산자?.로 접근한다는 점을 확인하세요. 이렇게 하면housingLocation이null이나undefined여도 애플리케이션에 오류가 발생하지 않습니다.Details클래스의 본문을 다음 코드와 같이 수정하세요:src/app/details/details.ts의 Details 클래스 수정하기
import {Component, inject} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {HousingService} from '../housing.service'; import {HousingLocationInfo} from '../housinglocation'; @Component({ selector: 'app-details', template: ` <article> <img class="listing-photo" [src]="housingLocation?.photo" alt="Exterior photo of {{ housingLocation?.name }}" crossorigin /> <section class="listing-description"> <h2 class="listing-heading">{{ housingLocation?.name }}</h2> <p class="listing-location">{{ housingLocation?.city }}, {{ housingLocation?.state }}</p> </section> <section class="listing-features"> <h2 class="section-heading">About this housing location</h2> <ul> <li>Units available: {{ housingLocation?.availableUnits }}</li> <li>Does this location have wifi: {{ housingLocation?.wifi }}</li> <li>Does this location have laundry: {{ housingLocation?.laundry }}</li> </ul> </section> </article> `, styleUrls: ['./details.css'], }) export class Details { route: ActivatedRoute = inject(ActivatedRoute); housingService = inject(HousingService); housingLocation: HousingLocationInfo | undefined; constructor() { const housingLocationId = Number(this.route.snapshot.params['id']); this.housingLocation = this.housingService.getHousingLocationById(housingLocationId); } }이제 선택한 주택에 맞는 정보를 표시하는 코드가 준비되었습니다.
constructor에서HousingService의getHousingLocationById함수를 호출하며 라우팅 파라미터를 인자로 전달합니다.다음 스타일을
src/app/details/details.css파일에 복사하세요:Details 스타일 추가하기
.listing-photo { height: 600px; width: 50%; object-fit: cover; border-radius: 30px; float: right; } .listing-heading { font-size: 48pt; font-weight: bold; margin-bottom: 15px; } .listing-location::before { content: url('/public/location-pin.svg') / ''; } .listing-location { font-size: 24pt; margin-bottom: 15px; } .listing-features > .section-heading { color: var(--secondary-color); font-size: 24pt; margin-bottom: 15px; } .listing-features { margin-bottom: 20px; } .listing-features li { font-size: 14pt; } li { list-style-type: none; } .listing-apply .section-heading { font-size: 18pt; margin-bottom: 15px; } label, input { display: block; } label { color: var(--secondary-color); font-weight: bold; text-transform: uppercase; font-size: 12pt; } input { font-size: 16pt; margin-bottom: 15px; padding: 10px; width: 400px; border-top: none; border-right: none; border-left: none; border-bottom: solid 0.3px; } @media (max-width: 1024px) { .listing-photo { width: 100%; height: 400px; } }그리고 변경 사항을 저장하세요.
Details에서 방금 만든details.css파일을 스타일 파일로 지정하세요:details.ts에서 생성한 CSS 파일 사용하기
import {Component, inject} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {HousingService} from '../housing.service'; import {HousingLocationInfo} from '../housinglocation'; @Component({ selector: 'app-details', template: ` <article> <img class="listing-photo" [src]="housingLocation?.photo" alt="Exterior photo of {{ housingLocation?.name }}" crossorigin /> <section class="listing-description"> <h2 class="listing-heading">{{ housingLocation?.name }}</h2> <p class="listing-location">{{ housingLocation?.city }}, {{ housingLocation?.state }}</p> </section> <section class="listing-features"> <h2 class="section-heading">About this housing location</h2> <ul> <li>Units available: {{ housingLocation?.availableUnits }}</li> <li>Does this location have wifi: {{ housingLocation?.wifi }}</li> <li>Does this location have laundry: {{ housingLocation?.laundry }}</li> </ul> </section> </article> `, styleUrls: ['./details.css'], }) export class Details { route: ActivatedRoute = inject(ActivatedRoute); housingService = inject(HousingService); housingLocation: HousingLocationInfo | undefined; constructor() { const housingLocationId = Number(this.route.snapshot.params['id']); this.housingLocation = this.housingService.getHousingLocationById(housingLocationId); } }브라우저를 새로고침하고 주택의 "Learn More" 링크를 클릭했을 때 해당 항목의 데이터에 맞는 상세 정보가 표시되는지 확인하세요.
-
Home으로 돌아가는 기능 확인하기앞선 실습에서
App템플릿에routerLink를 추가했습니다. 이 코드로 로고를 클릭할 때마다Home으로 돌아갈 수 있습니다.코드가 다음과 같은지 확인하세요:
app.ts의 routerLink 확인하기
import {Component} from '@angular/core'; import {Home} from './home/home'; import {RouterLink, RouterOutlet} from '@angular/router'; @Component({ selector: 'app-root', imports: [Home, RouterLink, RouterOutlet], template: ` <main> <a [routerLink]="['/']"> <header class="brand-name"> <img class="brand-logo" src="/public/logo.svg" alt="logo" aria-hidden="true" /> </header> </a> <section class="content"> <router-outlet /> </section> </main> `, styleUrls: ['./app.css'], }) export class App { title = 'homes'; }이미 작성한 코드이지만 올바른지 다시 확인하세요.
- 라우팅 파라미터로 이동할 화면에 데이터 전달하기
routerLink디렉티브로 동적 데이터를 사용한 경로 만들기- 라우팅 파라미터로
HousingService에서 데이터를 가져와 특정 주택 정보 표시하기
SUMMARY: 이번 실습에서는 상세 페이지를 표시하는 라우팅을 추가했습니다.
이제 다음 작업을 할 수 있습니다:
여기까지 잘 따라오셨습니다.
이 실습에서 다룬 내용을 더 알아보려면 다음 문서를 참고하세요: