【问题标题】:How to load a dynamic template into an angular component如何将动态模板加载到角度组件中
【发布时间】:2020-11-06 10:13:48
【问题描述】:

我需要能够通过 HTTP 请求获取模板 HTML,并让组件在该 HTML 中运行。

用例:我工作的公司拥有运行多租户的软件,并且需要一个 Angular 应用程序,该应用程序的一部分可以使用该软件按“主题”进行自定义。因此,我们需要定义一个默认模板,只要没有自定义的“主题”版本,就会使用该模板。我们在整个网站上都使用这种模式来显示许多视图/页面(使用液体)

我不需要只显示通过请求抓取的 HTML,这很简单,我需要专门将 HTML 注入一个可以做 Angular 事情的 Angular 组件中。

【问题讨论】:

    标签: angular typescript dynamic components


    【解决方案1】:

    我实际上找到了一个适合我们的解决方案,唯一的缺点是我们必须为该项目禁用 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

    【讨论】:

      猜你喜欢
      • 2017-07-19
      • 1970-01-01
      • 2022-01-04
      • 2017-10-10
      • 1970-01-01
      • 2017-10-12
      • 1970-01-01
      • 1970-01-01
      • 2019-03-27
      相关资源
      最近更新 更多