【问题标题】:How to inject an unique instance of a service in a dynamically created component?如何在动态创建的组件中注入服务的唯一实例?
【发布时间】:2021-10-04 05:58:24
【问题描述】:

我有一个 BaseComponent 和其他扩展它的组件,例如 WidgetComponent。

我使用ComponentFactoryResolver动态创建WidgetComponents。

BaseComponent 负责发出 http 请求,因此扩展组件可以通过包含 Observable 的公共属性访问响应。它使用SomeService 服务发出这些请求。

BaseComponent 在延迟加载模块中声明。

问题是,每次BaseComponent 发出请求时,每个扩展类都会收到响应,因为我认为我没有使用服务的唯一实例。

所以我的问题是,如何在每次动态创建 WidgetComponent 时使用不同的 SomeService 实例?

这是我的设置:

// BaseComponent.ts

import { InjectorService } from '@services/utils/injector.service';
import { SomeService } from '@services/some.service';

@Component({
    selector: 'base-widget',
    templateUrl: './base-widget.component.html'
})
export class BaseWidgetComponent {
    response$!: Observable<any>;
    someService: SomeService;

    constructor() {
        const injector = InjectorService.getInjector();
        this.someService = injector.get(SomeService);

        this.response$ = this.someService.getData();
    }
}

// 小部件组件

@Component({
    selector: 'widget',
    templateUrl: './widget.component.html'
})
export class WidgetComponent extends BaseWidget implements OnInit {
    ngOnInit() {
        this.response$.subscribe(console.log);
    }
}

// 一些服务

@Injectable({ providedIn: 'root' }) // I think this is not the correct way of providing it.
export class SomeService {
    constructor(private http: HttpClient) {}

    getData() {
        return this.http.get('url');
    }
}

// 注入器服务

import { Injector } from '@angular/core';

export class InjectorService {
    private static injector: Injector;

    static setInjector(injector: Injector) {
        InjectorService.injector = injector;
    }

    static getInjector(): Injector {
        return InjectorService.injector;
    }
}

// main.ts

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { InjectorService } from '@services/utils/injector.service';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
    enableProdMode();
}

(async () => {
    try {
        const moduleRef = await platformBrowserDynamic().bootstrapModule(AppModule);
        InjectorService.setInjector(moduleRef.injector);
    } catch (err) {
        console.error(err);
    }
})();

【问题讨论】:

  • 通过将服务添加到组件的providers 数组中,组件可以拥有自己唯一的服务实例。请参阅文档here。 “在组件中提供服务将服务仅限于该组件及其后代。同一模块中的其他组件无法访问它。”
  • 感谢您的回答。那么在这种情况下,组件的每个新实例都会有自己独特的服务实例?另外,我忘了提到一个重要的细节。该组件在延迟加载的模块中声明。我尝试在组件中提供服务,但出现“空注入”错误。
  • 这里的问题是您尝试使用继承,而 Angular 更适合与组合一起使用。长话短说,为什么不将 BaseWidgetComponent 中的代码导出到另一个 Service 中? (并使用 Angular DI 在您的组件中获取此服务)

标签: angular dependency-injection angular-dynamic-components


【解决方案1】:

在@Component 声明的providers 部分声明您的服务

@Component({
    selector: 'base-widget',
    templateUrl: './base-widget.component.html',
    providers:[SomeService]
    
})

这样每个组件实例都将获得SomeService的唯一实例

【讨论】:

  • 当组件是延迟加载模块的一部分时,这是否有效?
  • 是的。我唯一的疑问是providers 是否可以在基类上正常工作,或者它必须包含在继承它的每个组件中。如前所述,Angular 的组合更好,继承因此不必尝试。
猜你喜欢
  • 1970-01-01
  • 2017-04-16
  • 1970-01-01
  • 2017-01-07
  • 2018-07-05
  • 1970-01-01
  • 1970-01-01
  • 2018-07-04
  • 2020-01-06
相关资源
最近更新 更多