首页 文章

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

提问于
浏览
7

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

Note: I chose 3 different templates because controls vary based on the templateType where as single ts file as the inputs and logic for driving get and save of values in the template remains same. Hence I decided to go with 3 templates and a ts file as a single component.

//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.请提供替代方案,而不是附加不同的链接 .

2 回答

  • 0

    我实际上是想在我们说话的时候解决这个问题,当我看到上面的答案时,它给了我一个我即将尝试的想法 . 希望我能用它取得一些成功,并能够用更具体的东西更新这个答案 .

    我一直在研究我的问卷,我的问题是多项选择问题,包括措辞答案,多项选择问题,“1-10级”机制,然后是一些需要文本答案的问题 .

    我认为制作一个 component 并将每个模板包装在 ngIf 条件中,该条件连接到将传入数据的类中的变量可以触发模板 .

    所以数据看起来像这样

    Questions:[{
        question:'blahblahblah',
        answers: [..array of answers..],
        template: 'a'
        },
        {
        question: 'yaddayaddayadda',
        answers: [],
        template: 'b'
        },
        {
        etc.
        }
        ]
    

    然后在组件类中,您可以拥有这样的东西

    @Component ({
        selector: 'question-component',
        templateUrl: './template.html'
    })
    
    export class QuestionComponent {
    
        @input() data: yourDataType;
    
        constructor() {} 
    
    }
    

    然后在这个组件的模板中有类似的东西

    <div *ngIf="data.template === a">
        <!-- code for template with binding and everything -->
    </div>
    
    <div *ngIf="data.template === b">
        <!-- code -->
    </div>
    
    <!-- etc. etc. etc. -->
    

    然后在主要组件的模板中,您可以执行类似的操作

    <div *ngFor = "question of Questions">
        <question-component [data]="question"></question-component>
    </div>
    

    这一切都是我头脑中的假设,所以我可能会遗漏一些东西,但我觉得在此期间开始探索这件事是值得的 . 我要看看能不能满足我的需求 .

  • 7

    我知道这个问题很老,但希望这有助于那些尝试类似事情的人 .

    关于你想要什么的不幸的是,最简单的方法是简单地使每个模板成为自己的组件 . 否则,您必须注入并清理HTML . 由于注入未经过清理的HTML的安全风险,他们删除了ng-include和类似功能 . 如果您不必专门导入并声明模块中的所有其他组件,它就不会是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>) {  }
    }
    

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

    @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>;
    

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

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

相关问题