angular - 使用 Angular 4 在单个组件中加载动态模板

标签 angular angular4-forms

我的要求是构建一个具有 2 个或更多 html 模板的组件,其中每个 html 模板至少有 20 个控件,并且基于少数条件加载该特定模板。

注意:我选择了 3 个不同的模板,因为控件因模板类型而异,其中作为输入的单个 ts 文件以及驱动获取和保存模板中值的逻辑保持不变。因此,我决定将 3 个模板和一个 ts 文件作为一个组件。

//sub.component.ts
@Component({
     selector: 'sub-component',
     template: `
               <div [ngSwitch]="templateType">
                    <ng-template *ngSwitchCase="'1'"> ${require('./sub1.component.html')} </template>
                    <ng-template *ngSwitchCase="'2'"> ${require('./sub2.component.html')} </template>
                    <ng-template *ngSwitchCase="'3'"> ${require('./sub3.component.html')} </template>
                    <ng-template ngSwitchDefault> ${require('./sub1.component.html')} </template>
</div>
    `
})

我已经尝试了上面的替代方案,因为它看起来是实现该行为的简单解决方案,但编译失败并找不到要求。在 AngularJS 中,我们有 ng-Include 来填充任何模板,但它看起来 ng-template 不支持加载外部 html 内容。

请不要将此标记为重复,因为出现了许多与此类似的查询,但大多数解决方案已弃用或不适用于 Angular 4。请提供替代方案,而不是附加不同的链接。

最佳答案

我知道这个问题很老了,但希望这能帮助那些正在尝试类似事情的人。

关于您想要的不幸的是,最简单的方法是简单地使每个模板成为它自己的组件。否则,您必须注入(inject)并清理 HTML。他们删除了 ng-include 和类似的功能,因为注入(inject)未净化的 HTML 存在安全风险。如果您不必在模块中专门导入和声明所有这些附加组件,它就不会是 P.I.T.A,但是唉......

您可以创建一个简单的指令来获取 templateRefs,然后在您的页面上查询具有这些指令的元素,从中获取模板 ref,并将它们插入到其他地方。这至少可以让您将所有模板保存在一个单独的文件中。我通常将 3 或 4 个模板放在一个单独的组件中,并将它们包含在要使用 .我将描述如何做到这一点。

获取模板引用的指令

import { Directive, TemplateRef, Input } from '@angular/core';

@Directive({
 selector: 'get-template',
})
export class GetTemplateDirective {
  @Input() name: string;
  constructor(public template: TemplateRef<any>) {  }
}

然后对于模板,创建一个包含所有模板的 super 简单组件

@Component({
  selector: 'sub-component-templates',
  template: `

<ng-template get-template [name]="tpl1">
  Put Whatever here, including other components if you please
</ng-template> 

<ng-template get-template [name]="tpl2">
  Different template here
</ng-template> 

 ... and so on and so on...
`
})
export class Templates { }

将所有相关的新组件导入到您的模块中,然后将它们包含在将呈现模板的主组件中

我通常用 ng-content 来做,所以在父组件中很清楚这个组件正在为它的模板引用另一个组件。

例如,在父...

<sub-component>
    <sub-component-templates></sub-component-templates>
</sub-component>

然后在子组件中

 import { Component, ViewChild, ContentChildren, QueryList } from '@angular/core';
import { GetTemplateDirective } from 'wherever';

@Component({
selector: 'sub-component',
template: `

<ng-content></ng-content>

 <div #templateRenderer></div>
`
})
export class SubComponent {

@ViewChild('templateRenderer',{read:ViewContainerRef}) anchor: ViewContainerRef;
@ContentChildren(GetTemplateDirective) templates: QueryList<GetTemplateDirective>;

ngAfterContentInit()  {

  ... at this stage, you will have access to all the included templates with that directive on them. You can perform your logic to choose which one you want. Once you have selected the proper one, you can embed it like so ... 
 let desiredTemplateName = 'whatever';

     for (let t of this.templates.toArray()) {
       if(t.name === desiredTemplateName) {
          this.anchor.createEmbeddedView(t.template);
          break;        
       } 
     }  
   }

}

您可以看到,对于您要尝试做的事情来说,这太复杂了。将它们创建为单独的组件并使用 ngSwitchCase 来选择合适的组件会更容易。我上面描述的方法的优点是它可以让你把模板放在你真正想要的任何地方,并且你可以在同一个外部组件中包含 100 个(这实际上只不过是带有模板的最小装饰组件)如果你想要的,或者通过服务或其他方式移动它们。

有关如何使用编译器的工作示例,请参见此处 - https://plnkr.co/edit/fdP9Oc?p=info

还是比较复杂...

如果您将模板存储为类的属性,您可以稍后根据需要更改它。只需添加模板引用导入...

 import { Component, ViewChild, ContentChildren, QueryList, TemplateRef } from '@angular/core';

然后创建属性

 template: TemplateRef<any>;

然后您可以使用查询列表中的一个将其切换出来,并使用 View 容器的方法再次创建嵌入式 View 。

Angular 2/4 使某些事情变得更容易……并使某些事情变得更加困难。但我想在这种情况下,它是以安全的名义。

关于angular - 使用 Angular 4 在单个组件中加载动态模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44816333/

相关文章:

Angular2如何在另一个组件中使用一个组件的功能

angular - 如何制作标记界面或类似的东西

javascript - 多个输入字段之间的表单验证

javascript - Angular 2 CLI 变量未更新

forms - 我可以使用 ngxErrors 或类似的东西来显示表单错误吗?

javascript - 如何在另一个应用程序的 iframe 中包含 Angular 4 应用程序?

javascript - Angular 4 - 验证器自定义函数未定义

javascript - 基于一个数组对象键和其他数组对象值创建另一个新数组?

Angular 2+ removeAt 函数在子组件中不起作用