基于值的动态模板而不是带有 ngTemplateOutlet 的变量
Dynamic template based on value rather than variable with ngTemplateOutlet
我正在尝试模拟一组动态问题。想想一个测验,其中一个问题是选择题,第二个是单选题,第三个是是不是..等等
使用 angular 4.1,我认为使用 ngTemplateOutlet 进行模板化是最好的方法,我的想法是我可以将所有复选框的样式设置为相同,并且所有单选按钮都设置为相同等等
@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
如何修改此代码以使用变量的值来指示要使用的模板?
正如我在评论中所说,您必须通过 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);
}
}
我会改变方法,这是我的 2 美分:
为每种类型的选项(复选框、单选框、select 等...)创建一个组件。
将它们存储在常量中,将组件名称映射为字符串 class,例如:
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);
}
在组件的模板中:
<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"] }
];
总结:
- 我们创建一个 OptionsModule
- 我们为每个 option/question 类型创建一个组件(及其模板和逻辑)
- 我们在数据对象的
type
属性中添加这些组件的名称。 (或创建一个简单的映射方法:radio
-> TypeRadio
)
- 我们使用 NgComponentOutlet 来动态渲染我们的组件。
- 我们使用 NgModuleFactory 从导入的模块渲染这些组件。
结果:
我们的测验有一个动态组件加载系统。每个组件都有它的逻辑,并为您提供了添加很酷的功能和行为的巨大可能性!
这种方法的一个例子(我用它来获得 100% 的动态表单域:输入、select、单选按钮、复选框等):
**你可以稍微改变一下你的方法,因为它是一个可选的建议**
@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" 调用您的模板,其余结构在您的方法中看起来不错。
我正在尝试模拟一组动态问题。想想一个测验,其中一个问题是选择题,第二个是单选题,第三个是是不是..等等
使用 angular 4.1,我认为使用 ngTemplateOutlet 进行模板化是最好的方法,我的想法是我可以将所有复选框的样式设置为相同,并且所有单选按钮都设置为相同等等
@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
如何修改此代码以使用变量的值来指示要使用的模板?
正如我在评论中所说,您必须通过 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);
}
}
我会改变方法,这是我的 2 美分:
为每种类型的选项(复选框、单选框、select 等...)创建一个组件。
将它们存储在常量中,将组件名称映射为字符串 class,例如:
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);
}
在组件的模板中:
<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"] }
];
总结:
- 我们创建一个 OptionsModule
- 我们为每个 option/question 类型创建一个组件(及其模板和逻辑)
- 我们在数据对象的
type
属性中添加这些组件的名称。 (或创建一个简单的映射方法:radio
->TypeRadio
) - 我们使用 NgComponentOutlet 来动态渲染我们的组件。
- 我们使用 NgModuleFactory 从导入的模块渲染这些组件。
结果:
我们的测验有一个动态组件加载系统。每个组件都有它的逻辑,并为您提供了添加很酷的功能和行为的巨大可能性!
这种方法的一个例子(我用它来获得 100% 的动态表单域:输入、select、单选按钮、复选框等):
**你可以稍微改变一下你的方法,因为它是一个可选的建议**
@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" 调用您的模板,其余结构在您的方法中看起来不错。