代码之家  ›  专栏  ›  技术社区  ›  Rüdiger

http请求完全执行后单击Angular 7路由

  •  1
  • Rüdiger  · 技术社区  · 5 年前

    我有一个条目列表,当我点击其中一个列表时,我会进入一个更详细的项目视图。现在,该视图通过http请求加载(这比从一页到另一页的路由需要稍长的时间)。假设我有以下代码:

    对于目标页面:

     projectNumber: string = '';
    
      ngOnInit() {
      }
    
      constructor(
        private router: Router,
        private route: ActivatedRoute,
        private logger: LoggerService,
        private projectReceiverService: ProjectReceiverService
      ) {
        this.initProjectDataFromProjectNumber(this.route.snapshot.paramMap.get('projectNum'));
      }
    
      initProjectDataFromProjectNumber(projectNumber: string) {
        let project = this.projectReceiverService.getProjectByNumber(projectNumber); 
        this.projectNumber = projectNumber; //getProjectNumber => results in error
      }
    

    对于服务:

     getProjectByNumber(projectNumber: string): Project {
     let project: Project; 
     this.http.get(httpBaseUrl + "/project/getProject/" + projectNumber, httpOptions).subscribe((data) => {
      this.logger.info("Received data, processing...");
      project = data['projectDto'];
    },
    (error) => {
      this.logger.error("Error when receiving project.");
      this.logger.error(error.message);
    });;
     return project;
    }
    

    对于上一页(我在其中单击项目):

     projectClicked(projectNumber: string) {
        this.routeTo('projects/' + projectNumber);
      }
    

    现在,如果我能在http请求完全成功后设法进行路由,那就太好了(因为我可以在路由时直接传递项目对象,而且我也不会在显示一些可能尚未加载到详细页面的数据时遇到困难)。我怎么能这么做?我想在点击某个东西之前在前面加载它,但是如果之前加载每个项目的所有详细信息,那将是一个巨大的负担。

    1 回复  |  直到 5 年前
        1
  •  1
  •   Zlatko    5 年前

    使用route resolver可以相对轻松地完成此操作。

    事情是这样的。在路由配置中,提供路由路径、组件和 resolver .

    const routes = [{
      path: 'projects/:projectNumber',
      component: DestinationComponent,
      resolve: {
        project: ProjectResolver
      },
    }];
    

    提供您提到的解析器 . 例如,像这样:

    @NgModule({
      imports: [RouterModule.forChild(routes)],
      exports: [RouterModule],
      providers: [ProjectResolver],
    })
    export class ProjectDetailsModule {}
    

    但是这个项目解析器是什么?它只是一个可注入类,实现Angular的Resolve接口,该接口位于Angular的 resolve() 方法以数据、承诺或可观察的形式返回数据。看起来像这样:

    import { Injectable } from '@angular/core';
    import { Resolve } from '@angular/router';
    // You will also need your service
    import { ProjectService } from './project.service';
    
    @Injectable()
    export class ProjectResolver implements Resolve {
      // Inject it with where the data comes from
      constructor(private projectService: ProjectService) {}
    
      // Now implement the resolve interface. Angular will give you the route,
      // from which you can read the parameter.
      resolve(route: ActivatedRouteSnapshot): Observable<Project> {
        const projectNumber = route.snapshot.params['projectNumber'];
        return this.projectService.getProjectByNumber(projectNumber);
      }
    }
    

    现在,我们必须为您的服务修复一点问题-http方法通常是异步的,因此您必须返回可观察的:

    // I'll change the return type, from Project, to Obsevable<Project>
    getProjectByNumber(projectNumber: string): Observable<Project> {
      return this.http.get(`${ httpBaseUrl }/project/getProject/${ projectNumber }`,  httpOptions)
        // Instead of subscribe, you'll use a pipe, to map. So that others can actually subscribe (in our case the Angular router)
        .pipe(
          map(data => {
            this.logger.info("Received data, processing...");
            project = data['projectDto'];
            return project;
    
            // This whole `map(...)` part could have been a one-liner:
            // map(data => data.projectDto)
            // so alltogether:
            // this.http.get().pipe( map(data => data.projectDto), catchError(this.logger.error));
        },
        catchError(err => this.logger.error('Error getting project:', err.message)),
      );
    }
    

    // in the component
    ngOnInit() {
      this.activatedRoute.data.subscribe(project => this.project = project);
      // or something like this for immediate value:
      // this.data = this.route.snapshot.data;
    }
    

    请注意,这将保持页面处于“加载”状态,直到数据实际返回。如果您想并行获取数据,这是一个不同的答案,但也可以这样做。