如何使用Angular路由解析器

254 阅读7分钟

开始使用Angular路由解析器

构建Angular应用程序有时是很棘手的。这可能是由于在调用API后服务器响应延迟,或者是随后影响用户界面的bug。

在本教程中,我们将讨论Angular Route Resolvers在构建Angular组件中的重要性。我们还将创建一个示例应用程序,从API中获取一些数据,并在数据检索时才渲染组件。

教学目的

本教程涵盖了Angular路由解析器的基础知识到高级功能。最后,你应该能够进行API调用,并且只在收到数据响应时才解析路由。

前提条件

要继续学习本教程,你应该熟悉以下内容。

  • JavaScript或TypeScript的基础知识。
  • Angular2+路由概念的基础知识。
  • 依赖性注入的知识。

Angular API调用回顾

在我们进入实际话题之前,让我们回顾一下Angular的API调用。

通常情况下,当应用程序进行异步API调用时,需要一些时间来响应。这可能是由于网络不佳或服务器宕机。

无论是哪种情况,用户都会被重定向到一个没有API数据的组件。无论你是否有强大的网络连接,这种情况都会发生。

比如说。

...
import {Project} from "../models/project";

@Injectable({
  providedIn: 'root'
})
export class ApiService {

  constructor(private httpClient:HttpClient) { }

  /**
   * list of ministries
   */
  ListOfMinistries():Observable<Ministry>{
    return this.httpClient.get<Ministry>(`${environment.apiURL}ministries`);
  }

让我们假设上面的服务从一个国家的州政府获得所有部委的名单。我们已经注入了HttpClient 来帮助我们向服务器发送这个API请求。

我们也有一个监听我们的响应的可观察对象。GET 方法从服务器上获取所有部委的列表,并将该列表传递给Ministry 对象。

现在的问题是,我们不知道这要花多长时间。它是需要一秒钟还是半个小时,完全取决于我们所请求的服务器。

让我们看看,无论需要多长时间,我们如何处理这个响应。

只要我们有了这个响应,它就会像下面这个组件所示的那样处理。

.......
import {ApiService} from "../../core/services/api.service";
...
export class MinistriesComponent implements OnInit {
  ministries:Ministry[];
  //inject the api service we previously created.
  constructor(private apiService:ApiService,private router:Router) { }
  ngOnInit(): void {
    // list for ministries will be listed whenever this component is initialized
    this.getListOfMinistries();
  }
  /**
   * list of ministries
   */
  getListOfMinistries(){
    this.apiService.ListOfMinistries()
      .subscribe((res)=>{
        this.ministries=res.data;
      },error => {
      //error logs goes here...
      })
  }
}

在这个组件的开头,我们导入了我们之前创建的API服务。需要注意的是,这是一个依赖注入的概念,如果你很不熟悉的话,值得一看。

我们最初曾说过,是apiService ,用来与外部服务器通信,以获得所有部委的列表。

现在发生的情况是,我们把这个服务注入到我们的组件中,并按照我们的意愿使用它来获得各部委的列表,在我们的例子中,当MinistriesComponent 被初始化时。

为了有一个组织良好的组件,我们创建了一个方法getListOfMinistries() ,用来从apiService ,获得各部委的列表。

请记住,在依赖性注入中,我们可以在应用程序的任何地方注入一个服务的方法。因此,我们调用apiservice.ListOfMinistries() 方法来订阅来自API的各部委列表。

在其他因素不变的情况下,这应该在组件初始化时返回我们的部委列表,然而,情况并非总是如此。也许还有其他因素在起作用,比如服务器故障和网络连接不良。

我们在模板上的部委表会发生什么?对我们来说,重要的是要注意,每当一个组件被调用,它的模板就应该被渲染。

然而,在这种情况下,它的渲染没有来自API的部委列表,正如我们之前看到的那样,可能会有延迟。就用户界面而言,这破坏了整个页面,在那里应该显示列表。

如何防止这种情况呢?一个解决方案是在网站上实现加载器,当组件等待API的响应时,加载器将被加载。另一个解决方案是使用Angular路由解析器。

在下一节中,将深入介绍Angular解析器的概念。我们将看到如何使用这一功能来克服上述问题。

什么是Angular路由解析器?

更简单地说,Angular解析器指的是在组件完全加载之前执行的中间件

Angular路由解析器,就像一个过滤器,在一个组件被渲染之前,它必须确保它有该模板所需的数据。这当然可以确保在Angular中实现单页应用程序(SPA)。

现在,下面的模板渲染了没有加载器或路由解析器的部委列表。

<div class="table-responsive">
  <table class="table">
    <thead>
      <tr>
        <th>#</th>
        <th>Name</th>
        <th>Description</th>
        <th>Representative</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let ministry of ministries;let i=index">
        <td>{{i+1}}}</td>
        <td>{{ministry.name}}</td>
        <td>{{ministry.description}}</td>
        <td>{{ministry.representative}}</td>
      </tr>
    </tbody>
  </table>
</div>

在上面的模板上,我们有一个政府部委的表格。该表应该显示一个部委的名称,它的描述和部长。

通常情况下,当你试图循环浏览这个表时,你会发现这个表一开始是空的,但后来被数据填满了(我们假设API返回一些部委的列表)。

在你继续之前,测试一下上面的功能,以了解我们所说的 "延迟 "响应。

如果你成功地测试了上面的功能,你可能已经注意到破损的用户界面。这是一个公司很重视的用户界面问题,而你作为开发者必须有能力去修复。

正如你已经看到的,解决它的一个方法是使用Angular路由解析器。

现在我们希望我们的组件只有在有来自API的响应时才被显示(渲染)。在这一节中,让我们来实现路由解析器。

使用Angular路由解析器

之前,我们已经看到了不正确地处理API响应可能会破坏我们的用户界面。在这一节中,我们要用Angular路由解析器来实现同样的部委表,并注意其中的关键区别。

让我们先创建一个实现Resolver class 的类。

//ministries resolver
...
import {ApiService} from "../../core/services/api.service";
import { Resolve } from '@angular/router';
...
export class RouteResolver implements Resolve<any> {
  //inject the api service we initially implemented
   constructor(public apiService: ApiService) { }

  //resolve our list of ministries api service
   resolve() {
      return this.apiService.ListOfMinistries()
   }
}

在上面的类中,我们导入了我们设计的api服务。它有一个方法来获取所有政府部委的列表。我们在resolve() 方法中调用这个方法。

继续并编辑你的src/app/app-routing.module.ts ,如下所示。

.....
// Components
...
// Route resolver array
import { RouteResolver } from './resolvers/route.resolver';

const routes: Routes = [
  {
    path: 'ministries',
    component: MinistryComponent,
    resolve: {
      routeResolver: RouteResolver
    },
  },
];

@NgModule({
  ...
  providers: [RouteResolver]
})
....

在上面的路由模块中,我们导入之前创建的路由解析器来解析我们的部委列表。

然后我们创建一个类型为Routes 的路由常量。这个常量需要一个路由路径的数组,在我们的例子中,我们有一个单一的路由ministries ,它使用MinistryComponent ,并由RouteResolver 来解析。

现在我们已经将我们的ministries 路由配置为只返回已解析的数据,让我们看看我们如何在我们的组件上访问它。

更新MinistryComponent ,如下图所示。

...
import { ActivatedRoute } from '@angular/router';
...

export class MinistryComponent implements OnInit {
  ministries:Ministry[];
  constructor(
    private route: ActivatedRoute
  ) { }

  ngOnInit() {

    this.route.data.subscribe(data => {
      this.ministries=data;
      //log your api response here...
    })
  }
}

MinistryComponent ,我们已经导入了ActivatedRoute ,它只用于解析激活的路由。我们订阅了这个已解决的路由,并且只在我们有部委的数据时显示模板。

总结

在本教程中,我们已经看到Angular路由解析器是如何实现的。我们已经看到了它的优势,以及为什么我们倾向于避免直接从组件中访问API调用。