Angular:使用基于路由的动态InjectionTokens?

时间:2018-03-02 00:11:44

标签: angular service dependency-injection routing

我想知道如何初始化一个依赖于另一个服务的服务和一个用于在服务中实例化依赖关系的复杂对象。目前,我正在使用InjectionToken将复杂对象推送到服务中,但我需要动态地将不同的复杂对象推送到服务,具体取决于用户采用的路径

为了演示这个问题,假设我有一个依赖于HelperService的InterestingService和一个包含用于实例化内部服务类的参数的对象:

InterestingService

...
@Injectable()
export class InterestingService {

  interestingObject: InterestingObject;

  constructor(private helperService: HelperService,
              @Inject(PARMS) private parms: ParmsTemplate) {
    // parms e.g. {value1: 'aaa', value2: [1,2,3]}
    this.interestingObject = new InterestingObject(parms);
  }

  doSomething() {
    this.interestingObject.doSomethingAwesome()
  }
}

参数必须遵循特定格式:

ParmsTemplate

export interface ParmsTemplate {
  value1?: string,
  value2: number[]
}

该服务由组件使用:

SomeComponent

import { Component, OnInit } from '@angular/core';
import { InterestingService } from './interesting.service';

@Component({
  selector: 'app-some-component',
  templateUrl: './some.component.html',
  styleUrls: ['./some.component.css']
})
export class SomeComponent implements OnInit {

  constructor(public service: InterestingService) { }

  ngOnInit() {
    this.service.doSomething();
  }
}

InjectorToken定义以及一系列预定义的配方包含在PARMS中:

PARMS和罐装食谱

import { Injectable } from '@angular/core';
import { InjectionToken } from '@angular/core';
import { ParmsTemplate } from './parms';

export const PARMS = new InjectionToken<ParmsTemplate> ('parms.for.interesting.objects');

export const RECIPE_1: ParmsTemplate = {
  value1: 'aaa',
  value2: [1,2,3]
}

export const RECIPE_2: ParmsTemplate = {
  value1: 'bbb',
  value2: [1,2,3,4,5,6,7]
}

export const RECIPE_3: ParmsTemplate = {
  value2: [1,2]
}

在AppModule中初始化了InjectionToken:

的AppModule

...
import { RECIPE_1, RECIPE_2, RECIPE_3, PARMS } from './parms';
import { InterestingService } from './interesting.service';
import { HelperService } from './helper.service';

@NgModule({
  declarations: [
    SomeComponent
  ],

  imports: [
    BrowserModule,
    FormsModule,
    AppRoutingModule,
    HttpClientModule
  ],
  exports: [ ],
  providers: [
    InterestingService, 
    HelperService,
    {
      provide: PARMS, useValue: RECIPE_1
    }
  ],
  entryComponents: [ ],
  bootstrap: [AppComponent]
})
export class AppModule { }

最后,定义路线:

AppRoutingModule

...
import { NgModule }             from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { SomeComponent }     from './some.component';

const routes: Routes = [
  { path: 'recipe1', component: SomeComponent },
  { path: '', redirectTo: '/', pathMatch: 'full' },
  { path: '**', redirectTo: '/'}
];

@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule {}

这一切都很好,而且适用于一个食谱。我想做的是扩展我的路线以包括其他食谱:

...
const routes: Routes = [
  { path: 'recipe1', component: SomeComponent },
  { path: 'recipe2', component: SomeComponent },
  { path: 'recipe3', component: SomeComponent },
  { path: '', redirectTo: '/', pathMatch: 'full' },
  { path: '**', redirectTo: '/'}
];
...

问题是我的InjectionToken只能在AppModule中设置为一个值。

  1. 有没有办法根据路线指定要使用哪个InjectionToken?
  2. 我是否可以使用不同的方式来保持InjectionToken策略,但将不同的配方参数推送到我的共享服务中?
  3. 您认为这对工厂提供商来说是一个更好的工作吗?如果是这样,您如何建议我使用工厂提供商使用我的不同配方并为相关路线提供服务(例如/ recipe2将您带到SomeComponent,其中InterestingObject使用来自RECIPE_2的参数初始化InterestingObject)?
  4. 使用路线数据怎么样?如果是这样,您如何将路线数据注入服务? (实际上,这很容易,可能是最好的解决方案:将Route注入InterestingService,将配方作为其特定路由的路由数据传递,并使用route.data()获取服务中的配方数据。)

1 个答案:

答案 0 :(得分:0)

最后,我重构了我的代码以消除对基于路由的数据的需求,而是创建了一个服务来保存预制的配方并初始化InterestingObject。我对这个解决方案感到非常高兴。

在此之前,我能够使用路线数据,但我不得不使用ActiveRoute和不同的路线事件来获取组件中的数据。虽然这很有效,但它影响了我创建动态配方和重用组件的能力,因为尝试将数据推送到路径中是很尴尬的。这项服务显然是正确答案。

我将我的预制食谱设置为共享服务的方法。不幸的是,我不得不将它们设置为实例方法,以便HTML中的表达式可以引用它们。我尝试将它们设为静态变量,但表达式似乎看不到服务上的静态,但是它们可以看到实例引用没有问题。