【发布时间】:2023-02-04 15:37:46
【问题描述】:
我创建了一个图书馆使用注入服务的指令。该库在每个将要使用的延迟加载组件中加载了一个 forRoot 方法。
***图书馆.模块***
export const SERVICE_INYECTION_TOKEN: InjectionToken<any> = new InjectionToken('service')
export interface IDirectiveModuleConfig {
serviceAdapterConfiguration?: {provider: Provider, moduleName: string};
}
@NgModule({
imports: [
CommonModule
],
declarations: [DirectiveDirective],
exports: [DirectiveDirective]
})
export class LibraryModule {
public static forRoot(config: IDirectiveModuleConfig = {}): ModuleWithProviders<LibraryModule> {
console.log("Library loaded in module " + config.serviceAdapterConfiguration.moduleName)
return {
ngModule: LibraryModule,
providers: [
config.serviceAdapterConfiguration.provider
]
};
}
}
***指令.指令***
@Directive({
selector: '[directive]',
})
export class DirectiveDirective implements AfterViewInit {
@Input() methodName: string;
constructor(
private element: ElementRef,
private renderer: Renderer2,
@Inject(SERVICE_INYECTION_TOKEN) private service: any
) {}
ngAfterViewInit(): void {
this.element.nativeElement.innerText += this.service[this.methodName]()
this.renderer.setValue(this.element.nativeElement, this.service[this.methodName]())
}
}
在我的主要项目,我有两个延迟加载模块,每个模块都有一个组件。其中一个模块及其组件由 RouterModules 惰性加载。它工作正常
***app-routing.module***
const routes: Routes = [
{
path: 'a',
loadChildren: () =>
import('./modules/module-a/module-a.module').then((m) => m.ModuleAModule),
},
{
path: 'b',
loadChildren: () =>
import('./modules/module-b/module-b.module').then((m) => m.ModuleBModule),
},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
另一个是由compileModuleAndAllComponentsAsync()和viewContainerRef.createComponent()在父组件中。它在没有服务 inection 的情况下工作正常,但是当我注入服务时,我得到一个 NullInjectorError。
***应用组件***
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
@ViewChild("viewContainerRef", { read: ViewContainerRef }) viewContainerRef: ViewContainerRef
component = null;
title = 'component-overview';
constructor(private compiler: Compiler, private injector: Injector) {}
async createModuleAndComponetC() {
const componentInjector: Injector = Injector.create({providers:[{provide:'service', useExisting: ServiceCService}]})
this.viewContainerRef.clear()
const module = (await import('./modules/module-c/module-c.module'))
.ModuleCModule;
this.compiler.compileModuleAndAllComponentsAsync(module).then((factory) => {
factory.ngModuleFactory.create(this.injector);
const componentFactory = factory.componentFactories[0]
const component: ComponentRef<any> = this.viewContainerRef.createComponent(componentFactory);
});
}
}
模块A(由 routerModule 延迟加载工作正常)及其组件和服务
const serviceConfig: IDirectiveModuleConfig = {
serviceAdapterConfiguration: {
provider: { provide: SERVICE_INYECTION_TOKEN, useClass: ServiceAService },
moduleName: 'A',
}
};
@NgModule({
imports: [
LibraryModule.forRoot(serviceConfig),
CommonModule,
ModuleARoutingModuleModule,
],
declarations: [ComponentAComponent],
exports: [ComponentAComponent],
})
export class ModuleAModule {
constructor(){
console.log("moduleA loaded")
}
}
@Component({
selector: 'app-component-a',
templateUrl: './component-a.component.html',
styleUrls: ['./component-a.component.css'],
})
export class ComponentAComponent implements OnInit {
constructor() {}
ngOnInit() {}
}
@Injectable({
providedIn: 'root'
})
export class ServiceAService {
constructor() { }
serviceA(){
return(" service A!")
}
}
模块C(使用 compileModuleAndAllComponentsAsync() 和 viewContainerRef.createComponent() 手动加载
export const serviceConfig: IDirectiveModuleConfig = {
serviceAdapterConfiguration: {
provider: { provide: SERVICE_INYECTION_TOKEN, useClass: ServiceCService },
moduleName: 'C',
},
};
@NgModule({
imports: [CommonModule, LibraryModule.forRoot(serviceConfig)],
declarations: [ComponentCComponent],
})
export class ModuleCModule {
constructor() {
console.log('moduleC loaded');
}
static
}
@Component({
selector: 'app-component-c',
templateUrl: './component-c.component.html',
styleUrls: ['./component-c.component.css'],
providers: [ServiceCService],
})
export class ComponentCComponent implements OnInit {
constructor() {
console.log('component C constructor');
}
ngOnInit() {
console.log('component C OnInit');
}
}
@Injectable({
providedIn: 'root',
})
export class ServiceCService {
constructor() {}
serviceC() {
return ' service C!';
}
}
在此示例中,模块 A 和 B 与路由器插座一起使用,模块 C 加载了编译器,组件在 *ngCompilerOutlet 中使用
我认为问题出在我加载 ComponentC 的方式上……但我有点迷路了……
另外......我发现每次加载它时模块C都会创建一个新实例,并且不像单例那样工作......
【问题讨论】:
标签: dependency-injection lazy-loading angular12