와일드규칙
{path:'heroes', redirectTo:'superheroes'}
이런 리다이렉션 규칙은 잘 작동하지만 ...
const routes: Routes = [
{path:'', redirectTo:'heroes'},
{path:'heroes', component:HeroListComponent},
];
와일드규칙에 redirectTo하면 에러가 발생한다.
모든 일치를 리다이렉션할 수 없고 최소한의 조건으로 리다이렉션해야 한다.
{path:'heroes', component:HeroListComponent},
{path:'', redirectTo:'heroes', pathMatch:'full'},
가장 밑에 있어도 상관없이 작동한다.
라우팅영역과 라우트규칙
const routes: Routes = [
{path:'heroes', component:HeroListComponent},
{path:'hero/:id',component:HeroDetailComponent},
];
2개의 라우트규칙은 같은 라우팅영역을 사용한다.
즉 heroes url과 hero/:id url은 같은 라우팅영역에서 전환된다.
Router.navigate
navigate(commands: any[], extras: NavigationExtras = {
skipLocationChange: false }): Promise<boolean>
첫번째 인자는 배열형식으로 url(절대주소,상대주소)과 인자의 조합
두번째 인자는 NavigationExtras타입의 객체
router.navigate(['team', 33, 'user', 11], {relativeTo: route});
상대주소를 사용하면 NavigationExtras에 현재 route:ActivatedRoute를 같이 넘겨주어야 한다.
this.router.navigate(['team', 33, 'user', 11]);
상대주소를 사용하고 NavigationExtras을 사용하지 않으면 절대주소로 인식한다.
http://localhost:4200/team/33/user/11
id = 17;
this.router.navigate(['heroes',{id}]);
배열에 객체를 전달하면 메트릭스옵션인자로 전달된다.
http://localhost:4200/heroes;id=17
detailComponent에서 id값으로 세부데이터를 받아올때 옵저버블객체를 반환받은후 랜더링하는 방법
this.route.paramMap.subscribe(
params=>{
this.selectedId = params.get('id')!;
// 여기서 랜더링되어 undefined가 출력된다.
this.crisisService.getCrisis$(this.selectedId).forEach(
val=>{
this.crisis = val;
this.editName = val.name;
}
);
}
);
Resolve를 사용하면 컴포넌트 초기화전에 데이터화되어 받을 수 있다.
Resolve를 사용하는것이 좋다.
Resolve
Resolve가드라고 하지만 실제로는 서비스다.
ng g g test 했을때 resolve선택이 없다
export class CrisisDetailResolverService implements Resolve<Crisis> {
}
서비스를 생성하고 Resolve< Crisis>를 implements해야 한다.
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Crisis> {
}
resolve함수를 구현하면 되는데 여기서는 snapshot매개변수가 자동으로 주입되고 옵저버블객체를 반환한다.
라우트인자로 전달된 id를 얻은후 crisieService.getCriss$(id)로 Observable< Crisis>객체를 얻을 수 있다.
여기서 crisis의 존재여부를 검사하여 crisis가 없을때는 navigate함수로 다른 컴포넌트로 전화해야 한다.
let obs = this.crisisService.getCrisis$(id);
if(obs){
}else{
}
obs는 Observable< Crisis>이므로 데이터의 존재여부를 판단할 수 없다.
getCrisis$(id:string|number){
return this.getCrises$().pipe(
map(crises=>crises.find(crisis=>crisis.id == +id)!)
);
}
getCrisis$함수는 find함수가 crisie | undefined를 반환하고 map오퍼레이터가 옵저버블로 만들어 반환한다.
return this.crisisService.getCrisis$(id).pipe(
take(1),
map(crisis => {
if (!crisis) {
this.router.navigate(['/crisis-center']);
}
return crisis;
})
);
getCrisis$(id)함수가 Observable< Crisis> 아니면 Observable< undefined>를 반환하므로 map오퍼레이터를 사용하여 crisis가 undefined일때 라우터로 이동하면 된다.
this.route.data.subscribe(
data=>{
this.crisis = data['crisis'];
this.editName = this.crisis.name;
}
);
Resolve를 사용하면 route.data로 받을 수 있다.
canActivate가드는 컴포넌트를 랜더링하기전에 접근여부를 판단하여 랜더링할지를 결정한다.
{path:'',component:AdminCenterComponent,canActivate:[AuthGuard]}
위와 같이 canActivate가드를 라우트규칙에 추가한다.
라우트규칙은 모듈이 로드된후 작동하기때문에 canActivate가드는 모듈로드후에 동작한다.
모듈로드 소요시간을 단축하기 위해 모듈로드전에 canActivate가드처럼 어떤 동작을 해야 한다면 CanLoad가드를 사용해야 한다.
canActivate가드서비스가 만들어져 있다면 CanLoad가드를 따로 만들이 않아도 된다.
canLoad(route: Route, segments: UrlSegment[]): boolean {
if(!this.authService.isLoggedIn){
return false;
}
return true;
}
모듈로드를 제어할 수 있다.
지연로딩 : 어플리케이션시작시 로드되지않고 해당 모듈의 컴포넌트에 접근시 모듈이 동적로드되도록 설정한다.
{path:'crisis-center',loadChildren:()=>import('./crisis-center/crisis-center.module')
.then(m=>m.CrisisCenterModule)},
app-routing.module에 지연로딩을 라우트규칙으로 설정하며 app.module파일에서는 모듈import를 제거해야 한다.
사전로딩 : 어플리케이션시작후에 앵귤러가 지연로딩설정된 모듈들을 미리로드한다.
미리로드하면 모듈에 접근시 로드할 필요가 없어진다.
@NgModule({
imports: [RouterModule.forRoot(
routes,{preloadingStrategy: PreloadAllModules }
)],
exports: [RouterModule]
})
{preloadingStrategy: PreloadAllModules } 사전로딩 정책을 app.module에 명시한다.
커스텀사전로딩 : 사전로딩은 어플리케이션시작후 지연로딩된 모듈들을 전부 로드한다.
부하를 고려하여 선택적으로 사전로딩하도록 설정하는 것이 커스텀사전로딩이다.
{path:'crisis-center',loadChildren:()=>import('./crisis-center/crisis-center.module')
.then(m=>m.CrisisCenterModule),data: { preload: true }},
app-routing.module에 지연로딩설정이 되어있을때 data: { preload: true } 커스텀사전로딩 설정을 한다.
selective-preloading-strategy.service 서비스를 만든다.
export class SelectivePreloadingStrategyService implements PreloadingStrategy {
preloadedModules:string[] = [];
preload(route:Route, load: () => Observable<any>): Observable<any> {
if (route.data?.['preload'] && route.path != null) {
// 사전로딩할 모듈의 라우팅 규칙을 배열에 추가합니다.
this.preloadedModules.push(route.path);
// 라우팅 규칙을 확인하기 위해 콘솔에 출력합니다.
console.log('Preloaded: ' + route.path);
return load();
} else {
return scheduled([null],asyncScheduler);
}
}
constructor() { }
}
route.data?.['preload'] 커스텀사전로딩되도록 되어있는지 확인하고 사전로딩한다.
app.module에 커스텀사전로딩방식을 명시한다.
{preloadingStrategy: SelectivePreloadingStrategyService }
어플리케이션이 커질수록 커스텀사전로딩방식으로 모듈로드를 설정하는 것이 좋다.
this.sessionId = this.route.queryParamMap.pipe(
map(params=>params.get('session_id') || 'None')
);
this.token = this.route.fragment.pipe(
map(fragment=>fragment || 'None')
);
navigationExtras로 전달된 쿼리인자와 프레그먼트는 위와같이 받으면 된다.