You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中如何向带参数的InjectionToken传递组件参数?

问题

我定义了如下InjectionToken:

export const SOURCE_DATA_INJECTION_TOKEN =
    new InjectionToken<CustomObject[]>('All Source Data', {
      providedIn: 'root',
      factory: () => {
        // 返回全部源数据
        return someArrayData // 该数据读取自本地.json文件;
      }
    });

组件中直接使用该Token:

@Component({})
export class SourceManager {
  sourceDataList: CustomObject[] = inject(SOURCE_DATA_INJECTION_TOKEN);
}

现在需要升级这个INJECTION_TOKEN,使其根据组件中用户选择的源返回过滤后的数据。组件更新后如下:

@Component({})
export class SourceManager {
  selectedSource: SourceEnum = SourceEnum.SomeSource1

  sourceDataList: CustomObject[] = inject(SOURCE_DATA_INJECTION_TOKEN);
}

其中selectedSource可通过UI修改,我希望将该枚举值传入InjectionToken,使其返回过滤后的数据而非全部源数据。我注意到工厂方法可接收参数,请问能否将selectedSource传递给它?

解决方案

不能直接把组件的selectedSource传入InjectionToken的工厂方法,核心原因有两点:

  • inject()和Token的工厂方法都只在初始化阶段执行一次,后续selectedSource通过UI变更时,不会重新触发工厂方法生成新的过滤数据。
  • 根级提供的InjectionToken属于全局注入树的一部分,无法直接访问组件实例的私有状态(比如selectedSource)。

下面是两种更实用的实现方案:

方案一:用Angular信号(Angular 16+推荐)

通过服务管理源数据和选中状态,利用信号的自动响应特性实现数据实时更新:

@Injectable({ providedIn: 'root' })
export class SourceDataService {
  // 读取本地JSON的原始数据
  private readonly rawSourceData = someArrayData;
  // 存储选中源的信号,初始值设为默认枚举值
  readonly selectedSource = signal<SourceEnum>(SourceEnum.SomeSource1);
  // 计算信号:自动根据选中源过滤数据
  readonly filteredSourceData = computed(() => {
    return this.rawSourceData.filter(item => item.source === this.selectedSource());
  });
}

组件中使用:

@Component({})
export class SourceManager {
  private readonly sourceDataService = inject(SourceDataService);
  // 直接绑定服务的信号到模板,实现双向同步
  selectedSource = this.sourceDataService.selectedSource;
  // 获取实时过滤后的数据源
  sourceDataList = this.sourceDataService.filteredSourceData;

  // UI切换选中源时调用此方法
  onSourceChange(newSource: SourceEnum) {
    this.sourceDataService.selectedSource.set(newSource);
  }
}

方案二:用RxJS BehaviorSubject(兼容所有Angular版本)

通过可观察对象监听选中状态变化,自动推送过滤后的数据:

@Injectable({ providedIn: 'root' })
export class SourceDataService {
  private readonly rawSourceData = someArrayData;
  // 存储选中源的BehaviorSubject,自带初始值
  private readonly selectedSource$ = new BehaviorSubject<SourceEnum>(SourceEnum.SomeSource1);
  // 过滤后的数据源:通过pipe映射自动更新
  readonly filteredSourceData$ = this.selectedSource$.pipe(
    map(selected => this.rawSourceData.filter(item => item.source === selected))
  );

  // 更新选中源的方法
  setSelectedSource(source: SourceEnum) {
    this.selectedSource$.next(source);
  }
}

组件中使用:

@Component({})
export class SourceManager implements OnInit {
  private readonly sourceDataService = inject(SourceDataService);
  selectedSource: SourceEnum = SourceEnum.SomeSource1;
  sourceDataList: CustomObject[] = [];

  ngOnInit() {
    // 订阅过滤后的数据,自动更新组件列表
    this.sourceDataService.filteredSourceData$.subscribe(data => {
      this.sourceDataList = data;
    });
  }

  onSourceChange(newSource: SourceEnum) {
    this.selectedSource = newSource;
    this.sourceDataService.setSelectedSource(newSource);
  }
}

备选:基于组件实例提供Token(局限性大)

如果一定要保留InjectionToken的使用方式,可以为每个组件实例单独提供Token,依赖组件的selectedSource:

// 定义过滤数据的工厂函数
export function sourceDataFactory(selectedSource: SourceEnum) {
  const rawData = someArrayData;
  return rawData.filter(item => item.source === selectedSource);
}

// 组件内提供专属的Token实例
@Component({
  providers: [
    {
      provide: SOURCE_DATA_INJECTION_TOKEN,
      useFactory: () => sourceDataFactory(inject(SourceManager).selectedSource),
      deps: [SourceManager]
    }
  ]
})
export class SourceManager {
  selectedSource: SourceEnum = SourceEnum.SomeSource1;
  sourceDataList: CustomObject[] = inject(SOURCE_DATA_INJECTION_TOKEN);

  // 注意:这种方式下选中源变更后,需要手动更新数据
  onSourceChange(newSource: SourceEnum) {
    this.selectedSource = newSource;
    this.sourceDataList = sourceDataFactory(newSource);
  }
}

这种方式的问题是工厂方法仅在组件初始化时执行一次,无法自动响应selectedSource的变更,需要手动调用更新逻辑,仅适合简单场景。

内容的提问来源于stack exchange,提问作者itsji10dra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 03:42:51