动态模板基于值而不是使用ngTemplateOutlet变量

时间:2017-05-19 15:34:58

标签: angular ng-template

我正试图模拟一组动态的问题。想想一个测验,其中一个问题是多项选择,第二个是单一答案,第三个是是否..等等。

使用angular 4.1,我认为使用ngTemplateOutlet进行模板化是最好的方法,我的想法是我可以将所有复选框的样式设置为相同,并且所有的radiobutton都相同等。

@Component({
  selector: 'my-component',
  template: `
    <div *ngFor="let item of items">
        <ng-template [ngTemplateOutlet]="item.type" [ngOutletContext]="{ item: item }"></ng-template>
    </div>`
})
export class MyComponent {
  @Input() items: any[];
}

@Component({
  selector: 'my-app',
  template: `
    <div>
      <my-component [items]="questions">
        <ng-template #question let-item="item">{{item?.question}}</ng-template>
        <ng-template #check let-item="item">checkboxes here {{item?.type}} - {{item?.values}}</ng-template>
        <ng-template #radio let-item="item">radio buttons here{{item?.type}} - {{item?.values}}</ng-template>
        <ng-template #bool let-item="item">boolean here{{item?.type}} - {{item?.values}}</ng-template>
        <ng-template #textbox let-item="item">textbox here{{item?.type}} - {{item?.values}}</ng-template>
      </my-component>
    </div>`
})
export class App {
  @ViewChild('question') question;
  @ViewChild('type') type;
  @ViewChild('values') values;
  questions = [
      { question: "my checkbox question", type: "check", values: ["checkbox1","checkbox2","checkbox3","checkbox4"] },
      { question: "my radiobutton question", type: "radio", values: ["radio1","radio2","radio3","radio4"] } ,
      { question: "my boolean question", type: "bool", values: ["yes", "no"] } ,
      { question: "my textbox question", type: "textbox", values: ["maybe something maybe nothing"] } 
    ];

我已created this plunker as a proof of concept努力了,但它没有用。所有代码都在src/app.ts文件中。

我想要的是这样的:

My checkbox question?
checkbox 1, checkbox2, checkbox3

my radio button question
radiobutton1, radiobutton2, radiobutton3

my boolean question?
yes, no 

如何修改此代码以使用变量值来指示要使用的模板?

3 个答案:

答案 0 :(得分:7)

正如我在评论中所说,你必须通过TemplateRef ngTemplateOutlet财产。可以这样做:

@Directive({
  selector: 'ng-template[type]'
})
export class QuestionTemplate {
  @Input() type: string;
  constructor(public template: TemplateRef) {}
}

<强> app.html

<my-component [items]="questions">
  <ng-template type="question" ...>...</ng-template>
  <ng-template type="check" ...>...</ng-template>
  ...

<强> my.component.ts

@Component({
  selector: 'my-component',
  template: `
    <div *ngFor="let item of items">
        <ng-template 
           [ngTemplateOutlet]="dict['question']" 
           [ngOutletContext]="{ item: item }"></ng-template>
        <ng-template 
           [ngTemplateOutlet]="dict[item.type]" 
           [ngOutletContext]="{ item: item }"></ng-template>
    </div>`
})
export class MyComponent {
  @Input() items: any[];

  @ContentChildren(QuestionTemplate) templates: QueryList<QuestionTemplate>;

  dict = {};

  ngAfterContentInit() {
    this.templates.forEach(x => this.dict[x.type] = x.template);
  }
}

<强> Plunker Example

答案 1 :(得分:2)

我会改变方法,这里是我的2美分:

为每种选项类型创建一个组件(复选框,广播,选择等)。

将它们存储在常量中,将组件的名称映射为组件类的字符串,例如:

export const optionTypes = {
    'TypeRadio': TypeRadio,
    'TypeCheckBox': TypeCheckBox,
};

在组件中:

 private optionsModule: NgModuleFactory<any>; // we have our components for our options declared in OptionsModule, for example
 private optionTypes = optionTypes;

 constructor(private compiler: Compiler) {

        // Declaring Options Module
        this.optionsModule = compiler.compileModuleSync(OptionsModule);
 }

在Component的模板中:

<fieldset *ngFor="let question of questions">
                <ng-container *ngComponentOutlet="optionTypes[question.type];
                                    ngModuleFactory: optionsModule;"></ng-container>
            </fieldset>

请注意,为此,您的对象数据应更改type属性:

questions = [
      { question: "my checkbox question", type: "TypeCheckBox", values: ["checkbox1","checkbox2","checkbox3","checkbox4"] },
      { question: "my radiobutton question", type: "TypeRadio", values: ["radio1","radio2","radio3","radio4"] }
    ];

总结:

  1. 我们创建了一个OptionsModule
  2. 我们为每个选项/问题类​​型
  3. 创建一个组件(及其模板和逻辑)
  4. 我们在数据对象的type属性中添加这些组件的名称。 (或创建一个简单的映射方法:radio - &gt; TypeRadio
  5. 我们使用NgComponentOutlet动态呈现我们的组件。
  6. 我们使用NgModuleFactory从导入的模块中渲染这些组件。
  7. 结果:

    我们的quizz有一个动态组件加载系统。每个组件都有它的逻辑,为您提供添加酷炫功能和行为的巨大可能性!

    这种方法的一个例子(我用它来拥有100%动态表单域:输入,选择,单选按钮,复选框等)Angular2: Use Pipe to render templates dynamically

答案 2 :(得分:0)

**您可以稍微改变一下方法,因为这是可选建议**

@Component({
  selector: 'my-component',
 template: `
   <div *ngFor="let item of items">
      <ng-container [ngTemplateOutlet]="item.type" [ngTemplateOutletContext]="{ item: item }"> 
      </ng-container>
   </div>

    <ng-template #question let-item="item"></ng-template>
    <ng-template #check let-item="item">checkboxes here {{item?.type}} - {{item?.values}}</ng-template>
    <ng-template #radio let-item="item">radio buttons here{{item?.type}} - {{item?.values}}</ng-template>
    <ng-template #bool let-item="item">boolean here{{item?.type}} - {{item?.values}}</ng-template>
    <ng-template #textbox let-item="item">textbox here{{item?.type}} - {{item?.values}}</ng-template>
`
})
export class MyComponent {
  @Input() items: any[];
}

您可以基于“ item.type”调用模板的模板,其余结构在您的方法中看起来都很好。