首页 > 解决方案 > 在 Angular 中使用 Ag-grid 加载动态模块的问题

问题描述

我们是 Ag-Grid Enterprise 的消费者之一,我们围绕 ag-grid 编写了一个包装网格,以根据我们公司的规范添加自定义功能、逻辑和可重用性,并作为节点模块发布。

我们现在试图解决的主要要求之一是动态接收消费者构建的组件(在他们的项目中定义),将其提供给我们的包装网格,并以它期望的方式在内部将其提供给 ag-grid。

下面是更多解释它的代码片段。

消费者应用程序/AppModule.ts

  1. 下面的代码片段来自一个消费者项目 AppModule.ts,他们使用 ParentModule.forRoot(manifest) 导入我们的库。清单是其组件的一组路由。

  2. Manifest 对象具有 3 个属性 - componentId、path 和 loadChildren,它们特定于消费者应用程序中的组件。清单中可以有多个对象指向不同的组件。

const manifests: DynamicComponentManifest[] = [
  {
    componentId: 'message-icon',
    path: 'dynamic-message-icon-editors', // some globally-unique identifier, used internally by the router
    loadChildren: './dynamic-modules/message/message.module#MessageModule',
  }
];


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    FormsModule,
    ReactiveFormsModule,
    ParentModule.forRoot(manifests),
  ]
})

图书馆/ParentModule.ts

  1. 然后在我们库的 forRoot 静态方法中读取清单,以解析路由、DynamicComponentLoader 服务和 DYNAMIC_COMPONENT_MANIFEST InjectionToken。
  2. ParentModule 还导入了 gridModule,它导入了 AG-GRID 模块。

@NgModule({
    imports: [
        CommonModule,
        HttpClientModule,
        gridModule  // grid module is where Ag-grid is used
    ],
    exports: [ParentComponent],
    declarations: [ParentComponent],
    providers: [ParentComponentService, CommonServices, GRIDCONFIG],
    bootstrap: [ParentComponent]

})

export class ParentModule {
    constructor(){}
    static forRoot(manifests: DynamicComponentManifest[]): ModuleWithProviders {

        return {
            ngModule: ParentModule,
            providers: [
                DynamicComponentLoader,
                { provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader },
                // provider for Angular CLI to analyze
                { provide: ROUTES, useValue: manifests, multi: true },
                // provider for DynamicComponentLoader to analyze
                { provide: DYNAMIC_COMPONENT_MANIFESTS, useValue: manifests },
            ],
        };
    }
}

库/DynamicComponentLoader.ts

import { DYNAMIC_COMPONENT, DYNAMIC_COMPONENT_MANIFESTS, DynamicComponentManifest } from './dynamic-component-manifest';
    
    export class DynamicComponentLoader {
        constructor(
        @Inject(DYNAMIC_COMPONENT_MANIFESTS) private manifests: DynamicComponentManifest[],
        private loader: NgModuleFactoryLoader,
        private _injector: Injector,
        private _compiler: Compiler) {}
    
    /** Retrieve a ComponentFactory, based on the specified componentId (defined in the DynamicComponentManifest array). */
    
    getComponentFactory<T>(componentId: string, _injector?: Injector): Observable<ComponentFactory<T>> {
      const manifest = this.manifests
        .find(m => m.componentId === componentId);
      if (!manifest) {
        return ObservableThrow(`DynamicComponentLoader: Unknown componentId "${componentId}"`);
      }
    
      const p = this.loader.load(manifest.loadChildren)
        .then(ngModuleFactory => {
          const moduleRef = ngModuleFactory.create(_injector || this._injector);
          const dynamicComponentType = moduleRef.injector.get(DYNAMIC_COMPONENT);
          if (!dynamicComponentType) {
            throw new Error(
              `DynamicComponentLoader: Dynamic module for componentId "${componentId}" does not contain DYNAMIC_COMPONENT as a provider.`,
            );
          }
    
          return moduleRef.componentFactoryResolver.resolveComponentFactory<T>(dynamicComponentType);
        });
    
      return ObservableFromPromise(p);
    }

Library / Grid Module.ts • 在gridModule 中,我们尝试调用服务来获取组件工厂,然后将其提供给AgGridModule。

export function init_app(dynamicComponentLoader?: DynamicComponentLoader) {
    return dynamicComponentLoader.getComponentFactory()
        .subscribe(components => {
            const dynamicComp = components;

        }, error => {
            console.warn(error);
        });
}

@NgModule({
    imports: [
        CommonModule,
        HttpClientModule,
        FormsModule,
        AgGridModule.withComponents(init_app), // this accepts array of components
    ],
    exports: [GridComponent],
    declarations: [GridComponent],
    entryComponents: [],
    providers: [GridApiService],
    bootstrap: [GridComponent]

})


export class parentModule {
    constructor() {}
}

问题:

我们希望我们的消费者定义他们的组件以通过清单传递给 ag-grid 并将其传递给我们的库,我们可以在编译时解析并将其传递给 ag-grid。然而,我们觉得由于加载模块的角度生命周期,在AgGridModule.withcomponents()我们的ParentModule.forRoot(manifests). 此流程未加载 ag-grid,因为它未在编译时获取组件。我们如何解决这个问题,以便我们的 ParentModule 首先加载并准备好消费者应用程序的组件,然后传递给AgGridModule.withcomponents()

标签: angularangular5angular-cliag-gridag-grid-ng2

解决方案


推荐阅读