Angular12如何将组件@Input值传入注入服务,是否应使用ServiceFactory模式
Angular 12 动态将组件Input值注入对应服务实例实现方案
步骤1:调整DataStorageService配置与定义
首先移除服务的全局单例配置,新增dataType注入令牌,修正方法定义同时支持泛型适配不同的Item扩展类型:
import { InjectionToken } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { environment } from 'src/environments/environment'; import { Item } from '你的Item接口路径'; // 定义注入令牌,用于传递dataType参数 export const DATA_TYPE = new InjectionToken<string>('DATA_TYPE'); // 移除providedIn: 'root',不再使用全局单例 @Injectable() // 泛型约束适配不同Item扩展接口 export class DataStorageService<T extends Item> { // 若存在异步赋值场景可改为getter:private get apiEndpoint() private readonly apiEndpoint: string; constructor( @Inject(DATA_TYPE) private readonly dataType: string, private http: HttpClient ) { this.apiEndpoint = environment.config.urlLogin + '/api/' + this.dataType; } // 移除原代码多余的string参数 fetchAll(): Observable<T[]> { return this.http.get<T[]>(this.apiEndpoint); } }
步骤2:配置ListComponent组件级服务提供者
在组件的providers数组中通过工厂模式配置,实现每个组件实例对应独立的服务实例,自动注入当前组件的dataType输入值:
import { Component, Input, OnInit } from '@angular/core'; import { DataStorageService, DATA_TYPE } from '你的服务路径'; import { HttpClient } from '@angular/common/http'; import { Item } from '你的Item接口路径'; @Component({ selector: 'app-list', templateUrl: './list.component.html', styleUrls: ['./list.component.less'], // 组件级注册服务,每个<app-list>实例对应独立的服务实例 providers: [ { provide: DATA_TYPE, useFactory: (component: ListComponent) => component.dataType, deps: [ListComponent] }, { provide: DataStorageService, useFactory: (dataType: string, http: HttpClient) => new DataStorageService(dataType, http), deps: [DATA_TYPE, HttpClient] } ] }) export class ListComponent implements OnInit { @Input() dataType: string; items: Item[] = []; constructor(private ds: DataStorageService) { } ngOnInit(): void { // 修正原代码直接赋值Observable的错误,需订阅获取返回值 this.ds.fetchAll().subscribe(res => { this.items = res; }); } }
步骤3:使用方式
直接传入dataType属性即可,无需额外传参:
<app-list data-type="products"></app-list> <app-list data-type="orders"></app-list>
不同实例的DataStorageService会自动对应各自的dataType生成接口地址,互不干扰。
泛型扩展适配(可选)
如果需要针对不同dataType使用对应的扩展接口(比如Product extends Item),可以将ListComponent也改为泛型组件:
export class ListComponent<T extends Item> implements OnInit { @Input() dataType: string; items: T[] = []; constructor(private ds: DataStorageService<T>) { } // 其余逻辑保持不变 }
注意:如果存在
dataType异步赋值的场景,可将DataStorageService中的apiEndpoint改为getter属性,避免初始化时输入值还未赋值导致接口地址错误。
内容的提问来源于stack exchange,提问作者LBA
相关产品推荐
相关产品推荐

