【问题标题】:Angular 12. Inject service via forRoot into an external library, loaded from a module which has been lazy loaded by CompilerAngular 12.通过forRoot将服务注入外部库,从编译器延迟加载的模块加载
【发布时间】: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都会创建一个新实例,并且不像单例那样工作......

stackblitz with the test project

【问题讨论】:

    标签: dependency-injection lazy-loading angular12


    【解决方案1】:

    终于,我成功了!

    我看到我可以将注入器传递给 viewContainerRef。创建组件() 方法。我尝试使用与在 noModuleFactory 中创建模块时使用的注入器相同的注入器。 create()方法,但是还是报错。

    最后你意识到 NgModule 类导出了一个注入器,我假设这个注入器提供了这个模块中的所有提供者并且它工作正常!

    现在我的 createModuleAndComponetC() 是:

      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) => {
          const module = factory.ngModuleFactory.create(this.injector);
    
          const componentFactory = factory.componentFactories[0];
          const component: ComponentRef<any> =
            this.viewContainerRef.createComponent(
              componentFactory,
              0,
              module.injector
            );
        });
      }
    

    这是更正后的stackbliz

    【讨论】:

      猜你喜欢
      • 2021-11-29
      • 2019-09-03
      • 2018-06-19
      • 1970-01-01
      • 2017-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多