2016-05-14 77 views
6

我試圖創建一個使用角度2.一個非常簡單的例子一個表單生成如下:NG-含量的選擇變量綁定

this.fields = [{name: 'Name', type: 'text'}, {name: 'Age', type: 'number'}]; 

但我也想支持像自定義元素:

this.fields = [ 
    {name: 'Name', type: text}, 
    {name: 'Age', type: 'custom', customid: 'Ctl1'}, 
    {name: 'Whatever', type: 'custom', customid: 'Ctl2'} 
]; 
// template: 
<super-form [fields]="fields"> 
    <Ctl1><input type="number" ...><Ctl1> 
    <Ctl2><whaterver-control ...><Ctl2> 
</super-form> 

在我的表單生成組件然後我有類似:

<div *ngFor="let f of fields"> 
    <div [ngSwitch]="f.type"> 
    <span *ngSwitchWhen="'custom'">   
     <ng-content select="f.customid"></ng-content> 
    </span> 
    </div> 
</div> 

但考慮到我在這裏這顯然不不行。這是一個ng2限制嗎?如果是這樣,我想我可以硬編碼說5可選內容元素,並檢查他們是否指定,並沒有動態選擇,但這是一個黑客。

乾杯

回答

4

既然你綁定到一個變量,請使用單向綁定語法,如:

<ng-content [select]="f.customid"></ng-content>

修正
ng-content是靜態投影僅。它意味着快速「transcluding」。更多信息

+0

是的..試過了,選擇被忽略 – gatapia

+0

@gatapia對不起,它似乎'ng-content'只用於靜態投影。 [檢查這個問題](https://github.com/angular/angular/issues/8563) – Abdulrahman

+0

謝謝我剛剛發現,也。修改你的答案,並將其標記爲正確。 – gatapia

7

,如果你換一個<template>元素的內容你可以做到這一點已經請檢查this issue

// renders the template 
// `item` is just an example how to bind properties of the host component to the content passed as template 
@Directive({ 
    selector: '[templateWrapper]' 
}) 
export class TemplateWrapper implements OnChanges { 

    private embeddedViewRef:EmbeddedViewRef<any>; 

    @Input() 
    private item:any; 

    constructor(private viewContainer:ViewContainerRef) { 
    console.log('TemplateWrapper'); 
    } 

    @Input() templateWrapper:TemplateRef<any>; 

    ngOnChanges(changes:{[key:string]:SimpleChange}) { 
    if (changes['templateWrapper']) { 
     if (this.embeddedViewRef) { 
     this.embeddedViewRef.destroy(); 
     } 
     console.log('changes', changes); 
     this.embeddedViewRef = this.viewContainer.createEmbeddedView(this.templateWrapper, {item: this.item}); 
    } 

    if (this.embeddedViewRef) { 
     console.log('context', this.embeddedViewRef.context); 
     this.embeddedViewRef.context.item = this.item; 
    } 
    } 
} 
// just some component that is used in the passed template 
@Component({ 
    selector: 'test-component', 
    styles: [':host { display: block; border: solid 2px red;}'], 
    directives: [TemplateWrapper], 
    template: ` 
<div>test-comp</div> 
<div>prop: {{prop | json}}</div> 
    ` 
}) 
export class TestComponent { 
    @Input() prop; 

    constructor() { 
    console.log('TestComponent'); 
    } 
} 
// the component the `<template>` is passed to to render it 
@Component({ 
    selector: 'some-comp', 
    directives: [TemplateWrapper], 
    template: ` 
<div>some-comp</div> 
<div *ngFor="let f of fields"> 
    <div [ngSwitch]="f.type"> 
    <span *ngSwitchCase="'custom'">   
     <template [templateWrapper]="template" [item]="f" ></template> 
    </span> 
    </div> 
</div> 
    ` 
}) 
export class SomeComponent { 

    constructor() { 
    console.log('SomeComponent'); 
    } 

    @ContentChild(TemplateRef) template; 

    fields = [ 
    {name: 'a', type: 'custom'}, 
    {name: 'b', type: 'other'}, 
    {name: 'c', type: 'custom'}]; 
} 
// the component where the `<template>` is passed to another component 
@Component({ 
    selector: 'my-app', 
    directives: [SomeComponent, TestComponent], 
    template: ` 
<some-comp> 
    <template let-item="item"> 
    <div>some content</div> 
    <div>item: {{item | json}}</div> 
    <test-component [prop]="item"></test-component> 
    </template> 
</some-comp> 
    `, 
}) 
export class App { 
    constructor() { 
    console.log('AppComponent'); 
    } 
} 

Plunker example

+0

我正在嘗試,真的但我不能讓這個頭或尾巴。看起來你創建了一個模板(我猜可能是空的)並將其傳遞給測試組件。什麼是測試組件,是否應該是我傳遞給表單構建器的「動態元素」?這是否意味着對於我可能想要注入到表單構建器的每個元素,我需要給它一個[prop]輸入? – gatapia

+0

TestComponent只是我在傳遞給'SomeComponent'(可能是任何東西)的模板中使用的一些組件。我只是添加它來演示如何將傳遞的模板中的內容綁定到「SomeComponent」中的屬性。希望這可以幫助。如果您還有其他問題,我今天不會再回復。這是時候睡覺了。 'prop'的東西也只是一些例子,如何從模板綁定(如前所述),您不需要爲最簡單的情況添加它。 –

+0

@GünterZöchbauer這仍然是使用Angular 2.4.1的正確方法嗎? – Sebastian

9

我知道這是一個老問題,但是這是第一個地方之一此功能在搜索時我登陸所以我會補充我如何解決它。

ngContent僅用於靜態投影,因此您不能使用它來執行任何綁定。如果您需要綁定您的計劃內容,則可以使用ngTemplateOutlet和ngOutletContext。

用法示例:

<my-component> 
    <template let-item="item"> 
     <h1>{{item?.label}}</h1> - <span>{{item?.id}}</span> 
    </template> 
</my-component> 

裏面MyComponent的,你可以使用ContentChild訪問模板:

@ContentChild(TemplateRef) templateVariable: TemplateRef<any>; 

然後你的組件模板裏,你傳遞給ngTemplateOutlet這樣的:

<div *ngFor="let item of list"> 
    <template [ngTemplateOutlet]="templateVariable" [ngOutletContext]="{item: item}"></template> 
</div> 

ngOutletContext是可選的,但它允許您創建對象您將在模板中綁定。請注意,我在上下文對象中創建了一個屬性item。這匹配我放在模板上的名稱:let-item="item"

現在my-component的使用者可以傳入模板以用於列表中的每個項目。

貸款: 這answer帶領我在正確的方向。

+0

有沒有辦法將'Outlet'模板(與' let-item')在另一個組件中? - 不是直接在'my-component'內? – naomi

+0

@naomi。我不知道我是否明白你在做什麼,你是在談論html模板代碼還是控制器代碼?一旦你有了模板的句柄,你可以像其他變量一樣傳遞它,所以你只需要以某種方式得到它。例如,在我的用例中,我實際上必須將模板從另一個層次傳遞給孩子我的組件,所以我只是將它作爲輸入參數傳遞給子組件,然後我有模板在那裏使用它。 – Justin

+0

@naomi。如果您不希望您的項目模板位於標記內,則可以使用ViewChild從其他位置獲取它,但我沒有對其進行測試。 – Justin