首页 文章

Angular2中的动态组件选择[重复]

提问于
浏览
48

这个问题在这里已有答案:

给定一个包含多个字段的页面部分的模型,并使用如下数据填充:

{
    "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"
        }
    ]
}

我想有一个通用的部分组件,它不知道它可能包装的不同类型的字段,以避免部分模板中的大量条件逻辑,并通过放入自我来添加新的字段类型视图/组件包含文件,而不必修改单独的组件 .

我的理想是,Component的选择器足够具体,我可以通过基于绑定到模型的属性值在父Component的模板中选择一个元素来实现这一点 . 例如:(原谅任何语法问题,因为我在SO窗口中对此进行了编码,要注意的主要部分是BooleanComponent.ts上的选择器

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() {}
}

...随着时间的推移,我会添加新组件,为其他特定字段类型提供特殊模板和行为,甚至包含特定字幕的字段等 .

这不起作用,因为组件选择器必须是一个简单的元素名称(至少在alpha.26和alpha.27中) . 我对github对话的研究让我相信这个限制正在放松,但我无法确定我想要做什么实际上会得到支持 .

或者,我已经看到了一个提到的DynamicComponentLoader,但是现在我找不到我认为在angular.io指南上的例子 . 即便如此,我也不知道如何使用它来动态加载一个不知道名称或匹配条件的组件 .

有没有办法实现我的目标,使用类似于我尝试的技术或其他一些我在Angular 2中没有意识到的技术将专用组件与其父组件分离?

UPDATE 2015-07-06

http://plnkr.co/edit/fal9OA7ghQS1sRESutGd?p=preview

我认为最好显示我更明确地遇到的错误 . 我已经包含了一些带有一些示例代码的插件,但是这三个错误中只有第一个是可见的,因为每个错误都会阻挡另一个,所以你一次只能展示一个 . 我已经硬编码暂时绕过#2和#3 .

  • 我的BooleanComponent上的选择器是 selector: 'field[type=bool]' 还是 selector: '[type=bool]' ,我从Angular得到一个错误堆栈

组件'BooleanComponent'只能有一个元素选择器,但有'[type = bool]'

  • <field [type]="field.type"></field> 没有将我的field.type值绑定到type属性,但是给了我这个错误(幸好现在显示在alpha 28中 . 在alpha 26中,我之前在,它默默地失败了) . 我可以摆脱这个错误,我将一个类型属性添加到我的FieldComponent和衍生的BooleanComponent,并将其与@Component属性集合连接起来,但我不需要它用于组件中的任何内容 .

无法绑定到'type',因为它不是'field'元素的已知属性,并且没有匹配的指令与相应的属性

  • 我被迫在我的SectionComponent View注释的指令列表中列出FieldComponent和BooleanComponent,或者他们赢得了't be found and applied. I read design discussions from the Angular team where they made this conscious decision in favor of explicitness in order to reduce occurrences of collisions with directives in external libraries, but it breaks the whole idea of drop-in components that I' m试图实现 .

在这一点上,我很难理解为什么Angular2甚至不喜欢选择器 . 父组件必须知道它将具有哪些子组件,它们将去哪里以及它们需要什么数据 . 选择器目前是完全多余的,它也可以是类名匹配的约定 . 我没有看到我需要解耦它们的组件之间的抽象 .

由于Angular2框架能力的这些限制,我正在制作我自己的组件注册方案并通过DynamicComponentLoader放置它们,但我仍然非常好奇地看到有人找到了更好的方法来完成这个 .

3 回答

  • 0

    我想你可以使用Query / ViewQuery和QueryList来查找所有元素,订阅QueryList的更改并按任何属性smth过滤元素 . 像这样:

    constructor(@Query(...) list:QueryList<...>) {
       list.changes.subscribe(.. filter etc. ..);
    }
    

    如果你想绑定到类型,你应该这样做:

    <input [attr.type]="type"/>
    
  • 1
    • 如错误所示,组件必须具有唯一的选择器 . 如果要将组件行为绑定到属性选择器,就像使用 [type='bool'] 一样,则必须使用指令 . 使用 selector='bool-field'BoolComponent .

    • 如错误所示,您的通用 <field> 组件没有要绑定的 type 属性 . 您可以通过添加输入成员变量来修复它: @Input() type: string;

    • 您希望将组件模板委派给接收 type 属性的单个组件 . 只需创建通用组件,使用它的其他组件只需提供它,而不是它儿童 .

    示例: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>
    
  • 0

    它花了我一段时间,但我看到你试图做的事情没有在文档中涵盖,但可以请求 . 当前选项可以在under annotations from lines 419 - 426找到 .

    这个解决方案会过度选择导致一些误报,但试一试 .

    <field type="{{field.type}}"></field> 更改为 <field [type]="field.type"></field>

    然后选择属性:

    @Component({
      selector: '[type=bool]'
    })
    

相关问题