2017-06-29 3 views
1

私はタブビューを作成しようとしていましたが、コンテンツの投影が良いアプローチかもしれません。articleから学びました。私は、コンポーネントの配列を入力するだけで動的にすることができ、選択したタブのページとして表示されると考えました。 "EXCEPTION: Expression has changed after it was checked":ボタンのクリックハンドラは、このバグを避けるために他の機能を意図していないと()を追加し、子コンポーネントを動的に作成するときに、親コンポーネントの角2のContentChidrenが定義されていません。

@Component({ 
    selector: 'my-app', 
    template:` 
    <h1>Experiments</h1> 
    <button class="add-button" (click)="add()">Add</button>` 
}) 
export class App { 

    components:Array<any> = [PrepSetupTab,FinalizeTab] 

    constructor(private cdr: ChangeDetectorRef, 
       private compFR: ComponentFactoryResolver, 
       private viewContainer: ViewContainerRef){} 

    add():void{ 
     var transTabRefs: Array<any>= [] 

     this.components.forEach(tabComponent=>{ 

      let compFactory = this.compFR.resolveComponentFactory(tabComponent); 
      let compRef = this.viewContainer.createComponent(compFactory); 
      let tabFactory = this.compFR.resolveComponentFactory(Tab); 

      let transcludedTabRef = this.viewContainer.createComponent(tabFactory,this.viewContainer.length - 1, undefined, [[compRef.location.nativeElement]]); 
      transTabRefs.push(transcludedTabRef.location.nativeElement); 
     }) 

     let tabsFactory = this.compFR.resolveComponentFactory(Tabs); // notice this is the tabs not tab 
     this.viewContainer.createComponent(tabsFactory,0,undefined,[transTabRefs]); 

    } 


} 

サイドノート:ここで

は、これを行うに私の試みです。どんなライフサイクルフックに入れてもこのバグが出ます。それは後で対処するのが難しいですが。

基本的に私は配列内の各コンポーネントを作成していますが、作成したタブコンポーネントごとにそれらをng-contentとして貼り付けています。次に、各Tabコンポーネントを取得し、タブコンポーネントのng-contentに貼り付けます。

タブコンポーネントは、動的に作成されたタブの子のcontentChildrenを見つけられません。コンテンツの子が未定義のタブコンポーネントのコードは次のとおりです。

@Component({ 
    selector: 'tabs', 
    template:` 
    <ul class="nav nav-tabs"> 
     <li *ngFor="let tab of tabs" (click)="selectTab(tab)" [class.active]="tab.active"> 
     <a>{{tab.title}}</a> 
     </li> 
    </ul> 
    <ng-content></ng-content> 
    ` 
}) 
export class Tabs implements AfterContentInit { 

    @ContentChildren(Tab) tabs: QueryList<Tab>; 

    // contentChildren are set 
    ngAfterContentInit() { 
    // get all active tabs 
    let activeTabs = this.tabs.filter((tab)=>tab.active); 

    // if there is no active tab set, activate the first 
    if(activeTabs.length === 0) { 
     this.selectTab(this.tabs.first); 
    } 
    } 

    selectTab(tab: Tab){ 
    // deactivate all tabs 
    this.tabs.toArray().forEach(tab => tab.active = false); 

    // activate the tab the user has clicked on. 
    tab.active = true; 
    } 

} 

私がタブコンポーネントからコンテンツの子としてそれらにアクセスする必要がある場合にタブのコンポーネントは、その後、別の時に作成されていることを私にはかなり明確であるように思われます。私もChangeDetectionRef.changeDetect()を使ってみましたが、それは役に立ちません。

コンテンツプロジェクションを通してこれを行うのは、最も簡単な方法でもベストでもないので、私は提案をすることができます。ここにはplunk、ありがとう!

+0

'でそれを観察することができ、あなたのタブ

を初期化する可能性があります。これは設計によるものです – yurzui

+0

http://plnkr.co/edit/t1GnzDDR2s5g8PSDojXv?p=preview – yurzui

+0

Wow、InitContent私は前にそれを見たことがありません!そして、私は以前の大急ぎからそれを得たと思うので、あなたはこのコードのいくつかを認識するかもしれないと思うようになります:)。 –

答えて

0

@ContentChildrenは、動的に作成されるコンポーネントでは機能しません。

なぜ?

これは、投影の候補がコンパイル時にわかっている必要があるからです。ここ

は、コンポーネントのviewDefinitionで宣言されているノードを使用しContentChildren

function calcQueryValues(view, startIndex, endIndex, queryDef, values) { 
    for (var /** @type {?} */ i = startIndex; i <= endIndex; i++) { 
     var /** @type {?} */ nodeDef = view.def.nodes[i]; 
     var /** @type {?} */ valueType = nodeDef.matchedQueries[queryDef.id]; 
     if (valueType != null) { 
      values.push(getQueryValue(view, nodeDef, valueType)); 
     } 

を計算するために使用される機能です。 tabsコンポーネントをcreateComponent経由で作成し、プロジェクト可能ノードを手動で渡したときに、タブコンポーネントのファクトリがviewDefinitionに変更されていないため、角度が動的ノードを認識しません。

可能な解決策は、手動であなたが動的に作成コンポーネントでは動作しませんContentChildren` @このPlunkr

0

私がここに挙げた例を見てくださいdynamically add elements to DOM、多分あなたの問題のために役立つ何かを見つける。 plnkrのこの時点で、タブ配列は空です。

関連する問題