在Angular2中dynamic组件select
给定一个包含多个字段的页面部分的模型,并填充如下所示的数据:
{ "fields": [ { "id": 1, "type": "text", "caption": "Name", "value": "Bob" }, { "id": 2, "type": "bool", "caption": "Over 24?", "value": 0 }, { "id": 3, "type": "options", "options" : [ "M", "F"], "caption": "Gender", "value": "M" } ] }
我想有一个通用的部分组件,它不知道它可能包装的不同types的字段,以避免大量的章节模板中的条件逻辑,并通过放入自己添加新的字段types的视图/组件包含的文件,而不必修改一个单独的组件。
我的理想将是一个组件的select器是足够具体的,我可以通过在父组件的模板中select一个基于绑定到模型的属性值的元素来实现这一点。 例如:(赦免任何语法问题,因为我在SO窗口中编码,要注意的主要部分是BooleanComponent.ts上的select器
SectionComponent.ts
@Component({ selector: 'my-app' }) @View({ template: ` <section> <div *ng-for="#field of fields"> <field type="{{field.type}}"></field> </div> </section> `, directives: [NgFor] }) class SectionComponent { fields: Array<field>; constructor() { this.fields = // retrieve section fields via service } }
FieldComponent.ts:
// Generic field component used when more specific ones don't match @Component({ selector: 'field' }) @View({ template: `<div>{{caption}}: {{value}}</div>` }) class FieldComponent { constructor() {} }
BooleanComponent.ts:
// specific field component to use for boolean fields @Component({ selector: 'field[type=bool]' }) @View({ template: `<input type="checkbox" [id]="id" [checked]="value==1"></input>` }) class BooleanComponent { constructor() {} }
…随着时间的推移,我会添加新的组件,为其他特定的字段types提供特殊的模板和行为,甚至包含某些字幕的字段等。
这不起作用,因为组件select器必须是一个简单的元素名称(至less在alpha.26和alpha.27)。 我对github对话的研究使我相信这个限制正在放松,但我不能确定我想要做的事情是否真的会得到支持。
另外,我已经看到了一个DynamicComponentLoader,虽然现在我找不到我以为是在angular.io指南的例子。 即使如此,我也不知道如何dynamic加载一个不知道名称或匹配条件的组件。
有没有一种方法可以实现我的目标,即使用类似于我所尝试的技术或者我在Angular 2中没有意识到的其他技术,将专业组件与父项解耦?
更新2015-07-06
我认为最好的方式是更明确地显示我遇到的错误。 我已经包含了一些示例代码,但只有这三个错误中的第一个会显示出来,因为每个错误都会阻塞另一个,所以一次只能显示一个错误。 我已经硬编码来绕过#2和#3的时刻。
- 无论我在BooleanComponent上的
selector: 'field[type=bool]'
是selector: 'field[type=bool]'
还是selector: '[type=bool]'
,我从Angular得到一个错误堆栈
组件'BooleanComponent'只能有一个元素select器,但是'[type = bool]'
-
<field [type]="field.type"></field>
不绑定我的field.type值的types属性,但给我这个错误(现在谢天谢地显示在alpha 28中。在alpha 26我以前在,它失败了)。 我可以摆脱这个错误,我添加一个types属性到我的FieldComponent和派生的BooleanComponent,并与@Component属性集合,但我不需要它的任何东西在组件。
无法绑定到“type”,因为它不是“field”元素的一个已知属性,并且没有与相应属性相匹配的指令
- 我不得不在我的SectionComponent View注解的指令列表中列出FieldComponent和BooleanComponent,否则它们将不会被find和应用。 我从Angular团队那里阅读devise讨论,他们为了减less外部库中的指令碰撞事件而作出了明确的决定,但却打破了我试图实现的内置组件的整个想法。
在这一点上,我很难看出为什么Angular2甚至有麻烦select器。 父组件已经必须知道它将具有哪些子组件,它们将去哪里以及它们需要什么数据。 select器目前完全是多余的,这也可能是一个类名匹配的惯例。 我没有看到我需要解耦的组件之间的抽象。
由于Angular2框架的这些限制,我正在制作我自己的组件注册scheme,并通过DynamicComponentLoader来放置它们,但是我仍然非常好奇看到任何对于find更好的方法来完成这个任务的人的反应。
-
如错误所述,组件必须具有唯一的select器。 如果你想把组件行为绑定到属性select器,就像
[type='bool']
你必须使用指令。 为你的BoolComponent
使用selector='bool-field'
。 -
如错误所述,您的通用
<field>
组件没有要绑定的type
属性。 你可以通过添加一个input成员variables来修复它:@Input() type: string;
-
您想要将组件模板委托给接收
type
属性的单个组件。 只需创build通用组件,其他使用它的组件只需提供它,而不是其子组件。
例如: http : //plnkr.co/edit/HUH8fm3VmscsK3KEWjf6?p=preview
@Component({ selector: 'generic-field', templateUrl: 'app/generic.template.html' }) export class GenericFieldComponent { @Input() fieldInfo: FieldInfo; }
使用模板:
<div> <span>{{fieldInfo.caption}}</span> <span [ngSwitch]="fieldInfo.type"> <input *ngSwitchWhen="'bool'" type="checkbox" [value]="fieldInfo.value === 1"> <input *ngSwitchWhen="'text'" type="text" [value]="fieldInfo.value"> <select *ngSwitchWhen="'options'" type="text" [value]="fieldInfo.value"> <option *ngFor="let option of fieldInfo.options" > {{ option }} </option> </select> </span> </div>
我花了一段时间,但我看到你想要做什么。 基本上为ng2创build一个命令式的表单库,就像angular型一样。 您要做的不在文档中,但可以请求。 目前的选项可以在第419-426行的注释中find。
这种解决scheme将过度select导致一些误报,但试试看。
将<field type="{{field.type}}"></field>
更改为<field [type]="field.type"></field>
然后select属性:
@Component({ selector: '[type=bool]' })
我想你可以使用Query / ViewQuery和QueryList来查找所有元素,通过任何属性smth来订阅QueryList和过滤元素的更改。 喜欢这个:
constructor(@Query(...) list:QueryList<...>) { list.changes.subscribe(.. filter etc. ..); }
如果你想绑定types,你应该这样做:
<input [attr.type]="type"/>