angular - 在 Angular 中使用 Ag-grid 加载动态模块的问题
问题描述
我们是 Ag-Grid Enterprise 的消费者之一,我们围绕 ag-grid 编写了一个包装网格,以根据我们公司的规范添加自定义功能、逻辑和可重用性,并作为节点模块发布。
我们现在试图解决的主要要求之一是动态接收消费者构建的组件(在他们的项目中定义),将其提供给我们的包装网格,并以它期望的方式在内部将其提供给 ag-grid。
下面是更多解释它的代码片段。
消费者应用程序/AppModule.ts
下面的代码片段来自一个消费者项目 AppModule.ts,他们使用 ParentModule.forRoot(manifest) 导入我们的库。清单是其组件的一组路由。
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
- 然后在我们库的 forRoot 静态方法中读取清单,以解析路由、DynamicComponentLoader 服务和 DYNAMIC_COMPONENT_MANIFEST InjectionToken。
- 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()
?
解决方案
推荐阅读
- regex - Extract version number from string, optimal way?
- apache-kafka - 在 connect-distributed.properties 中设置 offset.storage.topic 以使用不同的服务器
- javascript - 正则表达式在多行文本中的下一个匹配开始处停止
- ios - App Store Connect 上的 6.5 英寸屏幕截图不接受在 iPhone XR 上制作的屏幕截图
- python - 如何用最后一个字符串重命名 xlsx 文件
- angular - 如何为事件发射器设置初始值
- python - 如何合并标题信息?
- php - 在 php codeigniter 中包含另一个页面时,父页面未加载
- android - 为什么我不能从推送通知意图触发的不同活动导航回我的原始活动?
- apache-kafka - 有没有办法在 Kafka 服务器的主题中始终保留最后一条消息?