angular - 如何将动态模板加载到角度组件中
问题描述
我需要能够通过 HTTP 请求获取模板 HTML,并让组件从该 HTML 中运行。
用例:我工作的公司拥有运行多租户的软件,并且需要一个 Angular 应用程序,该应用程序的一部分可以使用该软件根据“主题”进行定制。因此,我们需要定义一个默认模板,只要没有自定义的“主题”版本,就会使用该模板。我们在整个网站上都使用这种模式来显示许多视图/页面(使用液体)
我不需要只显示通过请求获取的 HTML,这很容易,我需要专门将 HTML 注入到一个可以执行 Angular 操作的 Angular 组件中。
解决方案
我实际上找到了一个适合我们的解决方案,唯一的缺点是我们必须禁用该项目的 AoT 编译。对于那些在我之后想要同样事情的人 - 这是我最终做了什么的快速概述。首先,在这里找到了我的解决方案的基础:https://stackblitz.com/edit/mlc-app-init-zyns9l?file=app%2Fapp.component.ts我将其放入共享助手中:
import { Component, NgModule, Compiler, ViewContainerRef, Type } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { SharedModule } from '../modules/shared.module';
export class DynamicComponentHelper {
public static addComponent<ViewModelType = any>(compiler: Compiler, container: ViewContainerRef, template: string, viewModel?: ViewModelType, components: Array<Type<any>> = []): void {
@Component({ template: template })
class DynamicComponent {
public vm: ViewModelType = viewModel;
constructor() { }
}
components.push(DynamicComponent);
@NgModule({
imports: [BrowserModule, SharedModule],
declarations: components
})
class DynamicComponentModule { }
const mod = compiler.compileModuleAndAllComponentsSync(DynamicComponentModule);
const factory = mod.componentFactories.find((comp) =>
comp.componentType === DynamicComponent
);
const component = container.createComponent(factory);
}
}
然后我有一个组件像这样调用它......
export interface VM { text: string; }
@Component({
selector: 'app-component',
template: `<ng-template #dynamicComponent></ng-template>`
...
})
export class VariationsComponent implements OnInit, AfterViewInit {
@ViewChild('dynamicComponent', { read: ViewContainerRef }) _container: ViewContainerRef;
private vm: VariationsComponentVM = { text: 'Hello World' }
private viewInitialized: boolean = false;
private componentTemplate: string;
constructor(private compiler: Compiler) { }
ngAfterViewInit(): void {
this.viewInitialized = true;
this.setUpDynamicComponent();
}
ngOnInit(): void {
this.httpService.getComponentTemplate().subscribe(template => {
this.componentTemplate = template;
this.setUpDynamicComponent();
});
}
private setUpDynamicComponent(): void {
if (this.viewInitialized === true && this.componentTemplate) {
DynamicComponentHelper.addComponent(this.compiler, this._container, this.componentTemplate, this.vm, [NestedComponent]);
}
}
}
然后实际使用的模板可能很简单...
<div>{{ vm.text }}</div>
<app-nested [input]="vm.text"></app-nested>
关于这一点的重要部分是所有内置的角度模板工作,所有指令和一切。再一次,唯一的缺点是你必须失去 AoT。是否可以/是否可以在组件级别禁用 AoT?如果我们可以在 AoT 中编译项目的大部分内容,但保留一个已定义的项目,那就太好了。
现在我的构建命令必须是:
ng build ProjectName --aot=false
ng build ProjectName --prod aot=false --build-optimizer=false
推荐阅读
- mysql - SELECT c.id WHERE org_id = x 并且所有日期列都是(NULL 或 < DATE_SUB(NOW(),INTERVAL 2 YEAR)?
- cmake - 如何在 CMake 中使用 find_package?(例如:GMP 库)
- arrays - 如何拆分具有逗号并更新为单独元素的字符串数组?
- c# - Visual Studio 2017:与 IBM.Data.DB2 的连接失败
- angular - 'e-columns' 不是已知元素:
- sql-server - 来自 XML 的数据 | SQL 服务器
- visual-studio - Azure Pipeline 未找到实际可用的包
- reactjs - antd 切换检查属性
- python - 需要帮助制作不和谐的音乐机器人
- jquery - 按钮单击事件未触发 JQuery 代码