【问题标题】:Angular 7 route on click after http-request got full performedhttp-request 完全执行后点击 Angular 7 路由
【发布时间】:2018-12-21 23:28:14
【问题描述】:

我有一个条目列表,当我单击一个列表时,我会进入该项目的更详细视图。现在这个视图通过 http-Request 加载(这比从页面到页面的路由要长一点)。所以假设我有以下代码:

对于目标页面:

 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 请求完全成功后以某种方式设法路由,那就太好了(因为我可以例如在路由时直接传递项目对象,而且我不会在显示一些数据时遇到困难可能尚未加载到详细页面上)。我怎么能那样做?我曾想过在点击某些内容之前将其加载到前一侧,但是之前加载每个项目的所有详细信息将是一个超载的地狱。

【问题讨论】:

    标签: angular httprequest angular-routing angular-http


    【解决方案1】:

    您可以使用路由解析器相对轻松地做到这一点。

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

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

    现在你必须把这条路线放在模块中,并提供你提到的解析器。例如。像这样:

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

    但是这个 ProjectResolver 是什么?它只是一个实现 Angular 的 Resolve 接口的可注入类,它的 resolve() 方法以数据、Promise 或 Observable 的形式返回数据。看起来像这样:

    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 方法通常是异步的,因此您必须改为返回 observable:

    // 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;
    }
    

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

    【讨论】:

    • 首先:感谢您的回答!只是为了澄清这一点:您提到了ProjectDetailsModule(我需要在其中添加解析器)。我的ProjectDetail 是一个组件,我没有它的模块 - 我需要在哪里添加它?在我的app.module.ts?编辑:如果我想并行获取数据,我需要在那里做什么?我知道这是一个不同的问题,但您能给我一个关键字或要查找的内容吗?
    • 几个问题:) 1. ProjectDetailsModule 只是一个路由模块,它为这个特定的东西设置路由。如果你不使用模块(你应该这样做,从长远来看它很容易并且很有帮助),那么只需将此路由添加到所有其他应用程序路由中 - 无论您的 RouterModule.forRoot(...) 在哪里。 2) 并行请求 - 与什么并行?两个http请求并行?查看 forkJoin。或者例如我刚刚为你创建的这个 StackBlitz:stackblitz.com/edit/…
    • 谢谢你,我去看看! :) 所以这意味着 - 基本上 - 我应该为每个组件创建一个模块?
    猜你喜欢
    • 2019-06-08
    • 1970-01-01
    • 2018-03-08
    • 2019-09-30
    • 1970-01-01
    • 1970-01-01
    • 2019-05-30
    • 2019-08-27
    • 2019-09-05
    相关资源
    最近更新 更多