如何在角度选项卡中加载动态组件?

时间:2017-12-15 03:23:01

标签: angular

我需要以角度方式将组件动态加载到选项卡中。我有一个父组件,其中有角度标签。在选项卡控件中,我需要动态加载子组件。

最初加载选项卡时,它应该加载一个组件1,并且在某些用户交互时,它应该触发事件,这将加载其他选项卡和其他子组件以加载到其中。

我的要求是在每个标签内动态加载任何子组件。

我在选项卡中动态加载子组件而不了解如何继续进行操作时遇到问题?

我已在stackblitz

中为演示创建了POC

我的父组件如下:

    import {Component, ViewChild, AfterViewInit, TemplateRef, ComponentRef, ViewContainerRef} from '@angular/core';
    import { ComponentFactoryResolver } from '@angular/core';
    import { Component1 } from './Component1';
    import { Component2 } from './Component2';

    @Component({
      selector: 'home',
      template: `<mat-tab-group class="demo-tab-group">
   <mat-tab *ngFor="let tab of homepageTabs; let i = index" label="{{tab.label}}">

          <!--Component1 and Component2 to be loaded here... what is the correct container object which can hold dynamic components ? -->

          <ng-template #container>{{tab.templateRef}}</ng-template>

    </mat-tab>
</mat-tab-group>`
    })
    export class HomeComponent {
      homepageTabs: any;
      @ViewChild('container', { read: ViewContainerRef }) dynamicTabPlaceholder;

      constructor(private cfr: ComponentFactoryResolver)
      {

        //Need to instantiate the components Component1 & Component2 dynamically and load here into the homepageTabs List
        const factory = this.cfr.resolveComponentFactory(Component1);
        const componentRef = this.dynamicTabPlaceholder.createComponent(factory);

         this.homepageTabs = [
          {
            label: 'HomeLabel',
            //templateRef: Component1,//How to assign the component1 instance here?
            tabTitle: 'HomeTitle'
          },
          {
            label: 'App Details',
            //templateRef: Component2,
            tabTitle: 'App Details'
          }
        ];
      }
    }

我的子组件如下所示,

import {Component} from '@angular/core';

@Component({
  selector: 'Component1',
  template: `Component1 Loaded

  <md-list>
  <md-list-item class="md-2-line" ng-repeat="item in workbookSheetsList">
    <md-checkbox ng-model="item.done"></md-checkbox>
    <div class="md-list-item-text">
      <h3>{{item.name}}</h3>
    </div>
  </md-list-item>
</md-list>
  `,
  //styleUrls: ['./tabs-template-label-example.css']
})
export class Component1 {

  workbookSheetsList = [{ "name": "TestReport" }, { "name": "SimpleReport" }, { "name": "Highlighting" }, { "name": "CalculatedColumns" }, { "name": "DateFormat" }, { "name": "KPIIndicator" }];

  constructor(){
  }
}

运行应用程序时出现以下错误,表示我无法获得正确的容器引用来创建/加载组件?

TypeError: Cannot read property 'createComponent' of undefined
    at new HomePageComponent (homepage.component.ts:76)
    at createClass (core.es5.js:10946)
    at createDirectiveInstance (core.es5.js:10764)
    at createViewNodes (core.es5.js:12205)
    at createRootView (core.es5.js:12100)
    at callWithDebugContext (core.es5.js:13486)

我很震惊,不知道如何加载要加载到选项卡中的子组件: -

  1. 什么是容器对象,它可以容纳放在
  2. 中的动态组件

    &#13;
    &#13;
    <mat-tab-group class="demo-tab-group">
           <mat-tab *ngFor="let tab of homepageTabs; let i = index" label="{{tab.label}}">
                <div class="demo-tab-content">
                  <!--Component1 and Component2 to be loaded here... what is the correct container object which can hold dynamic components ? -->
                 
                  <ng-template #container>{{tab.templateRef}}</ng-template>
                </div>
            </mat-tab>
        </mat-tab-group>
    &#13;
    &#13;
    &#13;

    1. 如何引用此容器对象并将动态组件分配到其中
    2. &#13;
      &#13;
          {
            label: 'HomeLabel',
            //templateRef: Component1,//How to assign the component1 instance here?
            tabTitle: 'HomeTitle'
          },
      &#13;
      &#13;
      &#13;

      有人可以帮我解决这个问题并让我知道如何继续进行吗?

      https://stackblitz.com/edit/angular-e7fnhd?file=app%2Fhome.component.ts

3 个答案:

答案 0 :(得分:0)

对于您动态创建的任何组件,您需要在ngModule中将它们添加为entryComponents。这是一个提示编译器包含工厂以在捆绑中创建它们。

@NgModule({
    declarations: [
       SomeDynamicComponent
    ],
    entryComponents: [
       SomeDynamicComponent
    ]
})

答案 1 :(得分:0)

尝试以下方法将子组件加载到另一个组件中。我做了如下操作,效果很好。

    this.entry.clear();
    const factory = this.resolver.resolveComponentFactory(Component1);
    const componentRef = this.entry.createComponent(factory);

答案 2 :(得分:0)

我认为这里的答案是使用Maybe路由器功能来加载您所引用的动态内容。

关键是我了解到很难的方法是将应用程序的主要组件设置为路由。因此,请勿将angular放在router-outlet文件中,而应将其作为index.html的元素。

Check out my stackblitz for a demo

这样,您还可以为应用程序构建静态布局,该布局在内部内容更改时保持不变。