[Angular2 Router] Resolving route data in Angular 2

本文介绍如何在 Angular 2 中使用路由解析器加载数据,包括创建解析器类、配置路由以及在组件中获取解析的数据。还讨论了使用 Observable 时需要注意的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

From Article: RESOLVING ROUTE DATA IN ANGULAR 2

Github

 

If you know Anuglar UI router, you must know resolve function in ui router, which you can load data before template and controller get inited. In Angular2 router, you can also use resovler. 

 

The recommended (personal preferred) way is use class to resolve the data, becasue you can inject servcie, so you can fetch data instead of hard cord data.

There is another way to use DI 'useValue'. Check out the article.

 

Create a resolver:

// hero-resolve.directive.ts


import {Resolve, ActivatedRouteSnapshot, RouterStateSnapshot} from "@angular/router";
import {Observable} from "rxjs";
import {StarWarsService} from "./heros.service";
import {Injectable} from "@angular/core";

@Injectable()
export class HeroDetailResolver implements Resolve<any> {

  constructor(private startWarsService: StarWarsService){

  }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | any{
    const id = route.params['id'];
    return this.startWarsService.getPersonDetail(id);
  }

}

 

After create the resovler, you can add to the providers:

@NgModule({
  imports: [
    CommonModule,
    herosRoutes
  ],
  declarations: [HerosComponent, HeroComponent],
  providers: [StarWarsService, CanHeroDeactivate, CanHeroActivateDirective, HeroDetailResolver]
})

 

Routers:

import {HerosComponent} from "./heros.component";
import {RouterModule} from "@angular/router";
import {HeroComponent} from "./hero/hero.component";
import {CanHeroDeactivate} from "./heros-can-deactivate.directive";
import {CanHeroActivateDirective} from "./heros-can-activate.directive";
import {HeroDetailResolver} from "./hero-resolver.directive";
const routes = [
  {path: '', component: HerosComponent},
  {
    path: ':id',
    component: HeroComponent,
    canDeactivate: [CanHeroDeactivate],
    canActivate: [CanHeroActivateDirective],
    resolve: {
      hero: HeroDetailResolver
    }
  },
];
export default RouterModule.forChild(routes)

Here 'hero' will be used to fetch data from router data.

 

Component:

import {
  Component,
  OnInit,
  OnDestroy,
  ViewChild,
} from '@angular/core';
import {ActivatedRoute, Router} from "@angular/router";
import {StarWarsService} from "../heros.service";
import {Observable, Subscription, BehaviorSubject} from "rxjs";

export interface Hero{
  name: string,
  image: string
}

@Component({
  selector: 'app-hero',
  templateUrl: 'hero.component.html',
  styleUrls: ['hero.component.css']
})
export class HeroComponent implements OnInit, OnDestroy {

  @ViewChild('inpRef') input;

  heroId: number;
  hero: BehaviorSubject<Hero>;
  description: string;
  querySub: Subscription;
  routeParam: Subscription;
  editing: boolean = false;

  constructor(private route: ActivatedRoute,
              private router: Router,
              private starwarService: StarWarsService) {

  }

  ngOnInit() {

    /* // Old way to get data from service when component inited
    this.hero = new BehaviorSubject({name: 'Loading...', image: ''});

    this.route.params
     .map((p:any) => {
      this.editing = false;
      this.heroId = p.id;
      return p.id;
     })
     .switchMap( id => this.starwarService.getPersonDetail(id))
    .subscribe( this.hero);*/

    // Here using resolver instead of fetch on fly
    this.routeParam = this.route.params
      .map((p:any) => p.id)
      .subscribe( (id) => {
        this.editing = false;
        this.heroId = id;
      });
    this.hero = this.route.data
      .map((d:any)=> d['hero']);
  }

  ngOnDestroy() {
    this.querySub.unsubscribe();
    this.routeParam.unsubscribe();
  }
}

 


Child route and access parnet's router resolver's data

  {path: ':url/:id', children: [
    {path: '', component: LessonDetailComponent},
    {path: 'edit', component: EditLessonComponent}
  ], resolve: {
    lesson: LessonDataResolver
  }},

For 'LessonDetailComponent' and 'EditLessonComponent' can both access the resolve data:

    this.route.data
      .subscribe(
        (res) => {
          this.lesson = res['lesson'];
        }
      )

 


ONE important note that: If return Observable from resolver, the observable should completed! Otherwise, it doesn't work. So why in the exmaple, it works, because $http.get(), it complete itself. 

But if you use AngualrFire2, you fetch data from Firebase like:

  findLessonByUrl(url){
     return this.angularFireRef.database.list('lessons', {
      query: {
        orderByChild: 'url',
        equalTo: url
      }
    })
    .filter(r => !!r)
    .map(res => res[0]);
  }

The observable doesn't complete itself, so in the resolver, you need to find a way to make the observable completed. 

For example:

import {Resolve, RouterStateSnapshot, ActivatedRouteSnapshot} from "@angular/router";
import {Observable} from "rxjs";
import {CourseService} from "../course.service";
import {Injectable} from "@angular/core";

@Injectable()
export class LessonDataResolver implements Resolve {
  constructor(private lessonService: CourseService){

  }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
    const url = route.params['id'];
    return this.lessonService.findLessonByUrl(url).first();
  }

}

Here it calls .first() to complete the observable. Or you can use '.take(1)'.

转载于:https://www.cnblogs.com/Answer1215/p/5947852.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值