简体   繁体   English

通过路由器将输入传递给 Angular 组件

[英]Pass input to Angular components via router

In Angular 2, I have my routes defined in app.module.ts :在 Angular 2 中,我在app.module.ts中定义了我的路由:

const appRoutes: Routes = [
  { 
    path: '',
    component: HomeComponent,
  },
  {
    path: 'admin',
    component: AdminComponent,
  }
];

I also have an app.component which displays the menu and a search form.我还有一个显示菜单和搜索表单的app.component This app.component is connected to a service ( events.service.ts ) which returns an array of events .app.component连接到返回events数组的服务 ( events.service.ts )。 When the search form is submitted, app.component calls the service to filter the events and then grabs them:当搜索表单提交时, app.component调用服务过滤事件然后抓取它们:

getEvents(): void {
    this.eventsService.getEvents().then(events => {this.events = events});
}

onSubmit() {
    this.searchTerm = this.model.searchTerm;
    this.eventsService.search(this.searchTerm).then(res => this.getEvents());
}

I would like to be able to pass this.events from the app.component down to the two routes specified in app.module ( home and admin ).我希望能够将this.eventsapp.component传递到app.module中指定的两个路由( homeadmin )。

My home.component.ts requires the same events.service.ts , and grabs events from it in an onNgInit function, but when the events in the service have been updated via the search in app.component.ts , the events grabbed in the initialisation of home.component.ts are out of date.我的home.component.ts需要相同的events.service.ts ,并在onNgInit函数中从中获取事件,但是当通过app.component.ts中的搜索更新服务中的事件时,在home.component.ts的初始化已过期。 I would like them to be synchronised.我希望它们是同步的。

You cannot directly pass data as "input" to the route.您不能直接将数据作为“输入”传递给路由。 Components which are placed "at the other side of" <router-outlet> are not visible in template, hence the notion of an "input" is not applicable in such cases.放置在<router-outlet> “另一侧”的组件在模板中不可见,因此“输入”的概念在这种情况下不适用。

The idea of router is to encode as much of application state as possible in the route.路由器的想法是在路由中编码尽可能多的应用程序状态。 Of course, you can implement some sort of caching to avoid multiple requests for the same resource that you expect to stay the same during reasonable amount of time.当然,您可以实现某种缓存来避免对同一资源的多次请求,您希望在合理的时间内保持不变。

Of course, not all data can be transferred through route.当然,并不是所有的数据都可以通过路由传输。 For example, you usually write only some sort of identification for an entity, and then use HTTP to bring more data down based on the ID read from the route.例如,您通常只为实体编写某种标识,然后使用 HTTP 根据从路由中读取的 ID 将更多数据带入。

That said, you can keep your data in a service.也就是说,您可以将数据保存在服务中。 From your component, save some data in a service instance which you've injected.从您的组件中,将一些数据保存在您注入的服务实例中。 Because services are singletons, when you inject the same service in a component which is used as a child route, you'll have the data placed in it from the parent route.因为服务是单例的,所以当您在用作子路由的组件中注入相同的服务时,您将从父路由中放置数据。

// componentA
this.service.data = data; // from http request, for example

// componentB
this.data = this.service.data;

Of course, depending on the timing of the operations above, it might happen that code in component B executes before code in component A, which means that you would grab undefined from Service#data .当然,根据上述操作的时间,可能会发生组件 B 中的代码在组件 A 中的代码之前执行的情况,这意味着您将从Service#data中获取undefined This is especially a common case if data is fetched asynchronously, which is often the case with HTTP requests.如果data是异步获取的,这种情况尤其常见,这通常是 HTTP 请求的情况。

For this, you can use observables, probably a BehvaiorSubject in order to grab data whenever you subscribe.为此,您可以使用 observables,可能是BehvaiorSubject ,以便在您订阅时获取数据。

// service
data$ = new BehaviorSubject<T>(null) // initial value as arg

// component A
this.service.data$.next(data) // from http request, for example

// component B
this.service.data$.subscribe(data => this.data = data)

Now your data in component B will update as soon as data is fetched in component A, though the data$ observable in the singleton service injected in both components.现在,只要在组件 A 中获取数据,组件 B 中的数据就会更新,尽管单例服务中的data$可观察到注入到两个组件中。

Be sure to unsubscribe as well, although you can use async pipe in Angular too.一定要取消订阅,尽管你也可以在 Angular 中使用async管道。 In that case, Angular will handle the unsubscription for you and in most cases this is the preferred way of using observables in Angular.在这种情况下,Angular 将为您处理取消订阅,并且在大多数情况下,这是在 Angular 中使用 observables 的首选方式。

Since angular 7.2.0 you can pass data through the router, using NavigationExtras从 Angular 7.2.0 开始,您可以使用NavigationExtras通过路由器传递数据

Add state to the route definition:将状态添加到路由定义中:

const appRoutes: Routes = [
  { 
    path: '',
    component: HomeComponent,
    state:{...}
  },
  {
    path: 'admin',
    component: AdminComponent,
  }
];

But, your app bootstraps from app.module.ts, this mean that when the app is setting up in app.module.ts the services aren't still availables, son you can't call the services yet.但是,您的应用程序从 app.module.ts 引导,这意味着当应用程序在 app.module.ts 中设置时,服务仍然不可用,儿子您还不能调用服务。

Option 1: Use a intermediate component, on the router you load HomeComponent_B or AdminComponent_B, and on that component, on the template you load the final component <app-homecomponent [events]="dat from services">选项 1:使用中间组件,在路由器上加载 HomeComponent_B 或 AdminComponent_B,在该组件上,在模板上加载最终组件<app-homecomponent [events]="dat from services">

Option 2: Better approach is use BehaivourSubject as sugested by @Lazar Ljubenović选项 2:更好的方法是使用@Lazar Ljubenović建议的 BehaivourSubject

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM