我们是Ag-Grid Enterprise的使用者之一,我们围绕ag-grid编写了包装网格,以根据我们公司的规范添加自定义功能,逻辑和可重用性,并作为节点模块发布。
我们现在要解决的主要要求之一是动态接收由使用者(在其项目中定义)构建的组件,将其馈送到包装器网格,并以预期的方式内部馈送到ag-grid
下面的代码段对其进行了详细说明。
消费类应用程序/ AppModule.ts
下面的代码片段是一个消费者项目AppModule.ts,他们在其中使用ParentModule.forRoot(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
•
@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);
}
库/网格模块.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()
?