zoukankan      html  css  js  c++  java
  • [Angular2 Router] Resolving route data in Angular 2

    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)'.

  • 相关阅读:
    Entity Framework Core 2.0 新特性
    asp.net core部署时自定义监听端口,提高部署的灵活性
    asp.net core使用jexus部署在linux无法正确 获取远程ip的解决办法
    使用xshell连接服务器,数字键盘无法使用解决办法
    使用Jexus 5.8.2在Centos下部署运行Asp.net core
    【DevOps】DevOps成功的八大炫酷工具
    【Network】Calico, Flannel, Weave and Docker Overlay Network 各种网络模型之间的区别
    【Network】UDP 大包怎么发? MTU怎么设置?
    【Network】高性能 UDP 应该怎么做?
    【Network】golang 容器项目 flannel/UDP相关资料
  • 原文地址:https://www.cnblogs.com/Answer1215/p/5947852.html
Copyright © 2011-2022 走看看