[angular] Component 간에 페이지(page) 이동하기 (router)

7 분 소요

Angular Routing

  • 홈페이지 작업시 프론트 엔드에서 기능해야할 필수 요소중 하나
  • 과거엔 <a> 태그로 하이퍼링크 달면 페이지 이동이 간단하게 구현되었지만, 컴포넌트간의 이동은 Angaulr 프레임워크로 구현한다.

  • Angular 프레임워크는 최초에 필요한 모듈과 필요한 서비스를 전부 들고 온 다음에, Routing 기능을 통해서 필요한 View 화면만을 불러와 기능하게 한다.

  • 페이지 이동시 Back 버튼 이동으로 History를 어떻게 구현해야될지 생각해야된다.

  • 딥링킹(Deep Linking) 이슈도 생각해야 한다. 예) http://blog.asdf.co.kr/list?category=1234” 같이 이런 파라미터에도 매개변수로 이동 할수 있도록 기능을 제공해야된다.



app-module.ts 에 Router 임포트

  • imports: 속성에 AppRoutingModule 을 추가한다.



AppRoutingModule 클래스를 새로 생성한다.

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router'; // 라우터 관련 심볼을 로드합니다.

const routes: Routes = []; // 라우팅 규칙은 이 배열에 등록합니다.

// NgModule의 imports, exports 배열에 RouterModule을 등록합니다.
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }



라우팅 규칙을 Routes 배열에 등록한다.

const routes: Routes = [
  { path: 'first-component', component: FirstComponent },
  { path: 'second-component', component: SecondComponent },
];
// path : 라우팅 규칙에 해당하는 URL 주소를 지정한다.
// 예) loaclhost:4200/first-component
// 예) localhost:4200/secont-component

// component : 해당 URL 주소에 연결될 컴포넌트를 지정한다.
...

export class AppRoutingModule{

}

라우팅 규칙을 애플리케이션에 등록한다.

  • 클릭 링크를 걸 HTML 파일에 라우트 속성의 <a> 태그를 등록한다.
<p>main-component!</p>
<h1>Angular Router App</h1>
<!-- 아래 링크를 클릭하면 AppRoutingModule에 등록된 라우팅 규칙에 따라 화면을 전환합니다. -->
<nav>
  <ul>
    <li><a routerLink="/first-component" routerLinkActive="active">First Component</a></li>
    <li><a routerLink="/second-component" routerLinkActive="active">Second Component</a></li>
  </ul>
</nav>
<!-- 라우팅된 화면은 <router-outlet> 위치에 표시됩니다. -->
<router-outlet></router-outlet>
<p>main-component end!</p>



실행화면)

angular_router1.png

  • 클릭시 해당 컴포넌트 url로 이동되며 페이지가 이동되는 것이 아니고 컴포넌트가 <app-main> <app-main> 태그 안쪽에 펼쳐진다.




라우팅 규칙으로 페이지 이동시에 정보(변수) 전달하는 방법

ActivatedRoute 인터페이스 활용

(1) 이동할 Component TS파일에 Router, ActivatedRoute, ParamMap 을 임포트한다.

import { Router, ActivatedRoute, ParamMap } from '@angular/router';

(2) 생성자에 ActivateRoute 인스턴스를 의존성으로 주입한다.

constructor(
  private route: ActivatedRoute,
) {}

(3) 생성자에 ActivatedRoute 객체안에 있는 id 인자를 참조한다.

ngOnInit() {
  this.route.queryParams.subscribe(params => {
    this.id = params['id'];
  });
}

전체코드)

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';

@Component({
  selector: 'app-board-detail',
  templateUrl: './board-detail.component.html',
  styleUrls: ['./board-detail.component.scss']
})
export class BoardDetailComponent implements OnInit {

  id : any | undefined;

  constructor(private route : ActivatedRoute) {

  }



  ngOnInit(): void {
    this.route.queryParams.subscribe(params => {
      this.idx = params['idx'];
    });
  }
}



URL의 쿼리 인자, 변수값 TS파일로 갖고 오는 방법

(1). app-routing.module 에 라우팅 규칙을 추가한다

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import {MainComponent} from "./page/main/main.component";
import {BoardDetailComponent} from "./page/board-detail/board-detail.component";
import {BoardListComponent} from "./page/board-list/board-list.component";
 // 라우터 관련 심볼을 로드합니다.



const routes: Routes = [
  {
    path: '',
    component: MainComponent
  },
  {
    path: 'detail/:idx',
    component: BoardDetailComponent
    // :(입력받을 변수)
  },
  {
    path: 'BoardList',
    component: BoardListComponent
  }
];

// NgModule의 imports, exports 배열에 RouterModule을 등록합니다.
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }


(2). 라우터 이동 이벤트에 변수 값을 등록한다.

[routerLink]="['/BoardList', 'detail', row.idx]"
//이러면 라우터 이동시에 boardList/detail/(row.idx) 값으로 이동되어진다.
// [ruouterLintk]= [url주소, 하위url주소, 하위url 주소 형식으로 매개변수값이 되어진다. 즉 url dpeth 지정가능


(3.) TS 파일에서 URL의 변수값을 가져온다.

  • this.route.snapshot.params[“(가져올 변수명)”] 사용
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';

@Component({
  selector: 'app-board-detail',
  templateUrl: './board-detail.component.html',
  styleUrls: ['./board-detail.component.scss']
})
export class BoardDetailComponent implements OnInit {

  postIdx : number | undefined;


  constructor(private route : ActivatedRoute) {
    this.postIdx = this.route.snapshot.params["idx"]
  }


  ngOnInit(): void {
    console.log("idx 변수값 : "+this.postIdx);
  }

}


자식 라우팅 규칙 적용하기

  • 애플리케이션이 점점 복잡해지다 보면 특정 컴포넌트 안에서 동작하는 라우팅 규칙을 추가하고 싶은 경우도 있다.
  • 이렇게 중첩된 라우팅 규칙을 자식 라우팅 규칙(child route)이라고 한다.
  • 라우팅 규칙을 중첩해서 적용하려면 컴포넌트에 <router-outlet>을 더 추가해야 한다.
  • 왜냐하면 첫번째 계층에서 동작하는 라우팅 규칙은 AppComponent의 <router-outlet>안에서 동작하기 때문이다.
  • 자식 라우팅은 페이지 이동이 아니고 컴포넌트가 컴포넌트 아래에 열리는 식으로 작동된다.
  • 예) 블로그에서 카테고리 선택하면 하위 카테고리 열리는 형식

첫번째로 이동할 라우팅 HTML 파일에 다음과 같이 작성한다.

<h2>First Component</h2>

<nav>
  <ul>
    <li><a routerLink="child-a">Child A</a></li>
    <li><a routerLink="child-b">Child B</a></li>
  </ul>
</nav>

<router-outlet></router-outlet>

그 다음에 AppRoutingModule TS파일에 다음과 같이 작성한다.

  • 자식 컴포넌트로 이동할 라우팅 규칙 추가
    const routes: Routes = [
    {
      path: 'first-component',
      component: FirstComponent, // 이 컴포넌트 템플릿에 <router-outlet>이 존재합니다.
      children: 
        [
          {
          path: 'child-a', // 자식 라우팅 규칙과 연결되는 주소
          component: SecondComponent, // 라우터가 렌더링하는 자식 컴포넌트
          }
        ],
    },
    ];
    


실행화면)

angular_router2.png

  • First Component 를 클릭하면 First Component 가 펼쳐지고, child A 를 클릭하면 Child A 컴포넌트가 그 아래에 펼쳐지는 형태.
  • url 주소 : http://localhost:4200/first-component/child-a

  • 아직까지 페이지 이동은 아니다.

  • 페이지 이동 하려면 HTML 템플렛에 <component></component> 대신 <router-outlet></router-outlet> 으로 작성해야 한다.

  • **최상위 HTML 에다가 <router-outlet>




URL 디자인 방법

1. Path Variable

  • 가공되지 않은 정적 자원을 특정해서 보여줄때 사용.
  • 예) users/1234
  • 특정 자원에 대한, 어떤것을 하자는 동사는 빠져있는데 그 역할을 하는 것이 HTTP 메소드이다.


2. Query Params

  • 어떤 자원을 재가공해서 정렬하거나, 필터링 해서 보여줄때,매개변수를 URL에 담아서 back end 에 보낼때 사용한다.
  • Path Variable 방식도 JSON 객체에 매개변수를 담아서 back end 에 보내줄 수 있지만, GET방식을 사용시에 JSON BODY를 담아서 보내는 방식은 지양해야되서 보통 Query Params 를 많이 사용한다.

  • 예) BoardList?page=1&option=content&word=testword


3. URL에서 동사는 사용하지 않는 것이 좋다.

4. 변수가 앞에오고, 그 뒤에 변수를 수식하는 단어가 오는것이 좋다.

예)BoardList/modify/:idx 형식이 아닌 BoardList/:idx/editor 형식으로. 페이지 번호가 앞에오고, 그뒤에 수식자가 옴




Angular Query Parms 방법으로 URL 라우팅하는 방법

참고 및 출저 :

https://www.digitalocean.com/community/tutorials/angular-query-parameters




app-routing-modules.ts 에 다음과 같이 설정한다.


app-routing-modules.ts

const routes: Routes = [
  { path: '', component: MainComponent },
  { path: 'BoardList', component: BoardListComponent }
  • 즉 BoardList 에 대한 Query를 하겠다는 것이다.
  • BoardList?page=1 이런식으로 Query 한다.


URL을 라우팅할 이벤트에 BoardList URL에 대한 queryParmas 를 지정한다.

  • 예)
router.navigate['Base URL 주소'], \{queryParams:}\{ 쿼리할key:쿼리value, 쿼리할key2:쿼리value2 ...}


BoardList.ts

this.router.navigate(['/BoardList'], {queryParams:{ page : this.page, search_option : this.FC_search_option, search_word : this.FC_search_word }});
    // URL을 클릭한 page 번호로 변경
  • 이벤트 발동시 BoardList?page=1&search_option=’title’&search_word=’테스트’ 형식으로 Routing 된다.





queryParams URL 에서 매개변수의 값을 가져오는 방법

  • activatedRoute.snapshot.queryParams 사용

예)

this.page = activatedRoute.snapshot.queryParams['page'] ?? 1;
// URL에서 BoardList?page=1 이면 'page' 에 해당하는 매개변수 값을 this.page 에 집어넣는다. null 값이면 1을 집어넣는다.


ActivatedRoute 객체

공홈 API 문서

https://angular.kr/api/router/ActivatedRoute#snapshot



ActivatedRoute Class

  • 아웃렛에 로드된 구성 요소와 연결된 경로에 대한 정보에 대한 액세스를 제공합니다. 이 명령을 사용하여 라우터 상태 트리를 이동하고 노드에서 정보를 추출합니다.


속성들

|Property|return Type|Descripton| |——–|———–|———-| |snapshot|ActivatedRouteSnapshot|이 경로의 현재 스냅샷| |url|Observable<UrlSegment[ ]>|이 경로와 일치하는 URL 세그먼트의 관찰 가능 항목입니다.| |params|Observable<Params>|이 경로로 범위가 지정된 행렬 매개변수의 관찰 가능 항목입니다.| |queryParams|Observable<Params>|모든 경로가 공유하는 쿼리 매개변수의 관찰 가능 항목입니다.| |fragment|Observable<string | null>|모든 경로에서 공유하는 URL 조각의 관찰 가능 항목입니다.| |data|Observable<Data>|이 경로의 정적 및 확인된 데이터의 관찰 가능 항목입니다.| |outlet|string|경로의 outlet 이름, 상수입니다.| |compoent|Type<any> | string | null|경로의 구성 요소, 상수입니다.| |routeConfig|Route | null|이 경로를 일치시키는 데 사용되는 구성입니다.| |root|ActivatedRoute|라우터 상태의 루트입니다.| |parent|ActivatedRoute | null|라우터 상태 트리에서 이 경로의 부모입니다.| |firstChild|ActivatedRoute | null|라우터 상태 트리에서 이 경로의 첫 번째 자식입니다.| |childern|ActivatedRoute[ ]|라우터 상태 트리에서 이 경로의 자식입니다.| |pathFromRoot|ActivatedRoute[ ]|라우터 상태 트리의 루트에서 이 경로까지의 경로입니다.| |paramMap|Observable<ParamMap>|경로에 특정한 필수 및 선택적 매개변수의 맵을 포함하는 Observable입니다. 맵은 동일한 매개변수에서 단일 및 다중 값 검색을 지원합니다.| |queryParamMap|Observable<ParamMap>|모든 경로에 사용할 수 있는 쿼리 매개변수의 맵을 포함하는 Observable입니다. 맵은 쿼리 매개변수에서 단일 및 다중 값 검색을 지원합니다.|



ActivatedRouteSnapshot Class

  • 특정 시점에 outlet에 로드된 구성 요소와 연결된 경로에 대한 정보를 포함합니다. ActivatedRouteSnapshot을 사용하여 라우터 상태 트리를 탐색할 수도 있습니다.

속성들

Property return Type Descripton
routeConfig Route| null 이 경로와 일치하는 데 사용되는 구성 *
url UrlSegment[ ] 이 경로와 일치하는 URL 세그먼트
params Params 이 경로로 범위가 지정된 행렬 매개변수입니다.
queryParams Params 모든 경로에서 공유하는 쿼리 매개변수 value
fragment string | null 모든 경로가 공유하는 URL 조각
data Data 이 경로의 정적 및 확인된 데이터
outlet string 경로의 outlet 이름
component Type<any>|string|null 경로의 구성 요소
root ActivatedRouteSnapshot 라우터 상태의 루트
parent ActivateRouteSnapshot|null 라우터 상태 트리에서 이 경로의 부모
firstChild ActivatedRouteSnapshot | null 라우터 상태 트리에서 이 경로의 첫 번째 자식
children ActivatedRouteSnapShot[ ] 라우터 상태 트리에서 이 경로의 자식
pathFromRoot ActivatedRouteSnapshot[ ] 라우터 상태 트리의 루트에서 이 경로까지의 경로
paramMap ParamMap Read-Only
queryParamMap ParamMap Read-Only



Params 자료형

type Params = {
    [key: string]: any;
};




Routing 규칙도 순서가 있다.

app-routing-modules.ts 에 각 컴포넌트당 URL 주소 등록시에, 등록된 순서대로 라우팅 규칙이 적용된다.


예제)

  • BoardList/create 로 이동시에 BoardDetailComponent로 이동이 되어진다.
  • BoardList/:idx 가 먼저 적용되어져서 create가 매개변수 value로 작용되어지기 때문
const routes: Routes = [
  { path: '', component: MainComponent },
  { path: 'BoardList', component: BoardListComponent },
  { path: 'BoardList/:idx', component: BoardDetailComponent },
  { path: 'BoardList/create', component: BoardCreateComponent }
];



올바르게 순서 적용한 예제

  • BoardList/create 가 위에 있어서 규칙이 먼저 적용된다.
  • 정상적으로 BoardList/create 페이지로 이동이 되어진다.
    const routes: Routes = [
    { path: '', component: MainComponent },
    { path: 'BoardList', component: BoardListComponent },
      { path: 'BoardList/create', component: BoardCreateComponent },
    { path: 'BoardList/:idx', component: BoardDetailComponent }
    ];
    




라우트가드

  • 프론트엔드도 백엔드 처럼 Token의 권한에 따라 페이지를 리다이렉트 시킬수 있다.

  • [path : '**’ ] 같이 path 값에 *를 붙이면 된다.

  • 프론트에서 리다이렉트 처리를 한다고 해서 백엔드는 안해야 되는게 아니다. 백엔드도 해야된다.

  • post man 같이 API 호출할수 있기 때문에, 프론트 엔드와 백엔드 둘다 인증 권한에 따라 리다이렉트 처리를 해줘야 한다.