简体   繁体   English

在Angular 2中使用ComponentResolver具有动态内容的动态选项卡

[英]Dynamic Tabs with dynamic content using ComponentResolver in Angular 2

Inspired by Angular 2 dynamic tabs with user-click chosen components and Passing Input while creating Angular 2 Component dynamically using ComponentResolver I'm trying to go one step further and have not just the tabs get a dynamic component but also the content of be tab be comprised of dynamic components. 受到Angular 2动态选项卡的启发,用户单击选择的组件在使用ComponentResolver动态创建Angular 2组件时传递输入我正在尝试进一步,不仅这些选项卡获得了动态组件,而且be选项卡的内容由动态组件组成。 From the original example I used components C1-C3 for the tabs and want to use C4 and C5 for sections. 在原始示例中,我将组件C1-C3用于选项卡,并希望对部分使用C4和C5。 I'm aware there isn't any styling/functionality for actually tabbing but the structure should be enough to get me on my way. 我知道实际的制表符没有任何样式/功能,但是结构应该足以让我前进。 I made this. 我做的。

//our root app component
import {Component, ComponentRef, Input, ViewContainerRef, ComponentResolver, ViewChild, Injectable, OnInit} from '@angular/core';

@Component({
  selector: 'dcl-wrapper',
  template: `<div #target></div>`
})
export class DclWrapper {
  @ViewChild('target', {read: ViewContainerRef}) target;
  @Input() type;
  cmpRef:ComponentRef;
  private isViewInitialized:boolean = false;

  constructor(private resolver: ComponentResolver) {}

  updateComponent() {
    if(!this.isViewInitialized) {
      return;
    }
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
    this.resolver.resolveComponent(this.type.type).then((factory:ComponentFactory<any>) => {
      this.cmpRef = this.target.createComponent(factory);
      this.cmpRef.instance.info = this.type;
    });
  }

  ngOnChanges() {
    this.updateComponent();
  }

  ngAfterViewInit() {
    this.isViewInitialized = true;
    this.updateComponent();  
  }

  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }    
  }
}

@Component({
  selector: 'child-dcl-wrapper',
  template: `<div #target></div>`
})
export class ChildDclWrapper {
  @ViewChild('target', {read: ViewContainerRef}) target;
  @Input() type;
  cmpRef:ComponentRef;
  private isViewInitialized:boolean = false;

  constructor(private resolver: ComponentResolver) {}

  updateComponent() {
    if(!this.isViewInitialized) {
      return;
    }
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
    this.resolver.resolveComponent(this.type.type).then((factory:ComponentFactory<any>) => {
      this.cmpRef = this.target.createComponent(factory);
      this.cmpRef.instance.info = this.type;
    });
  }

  ngOnChanges() {
    this.updateComponent();
  }

  ngAfterViewInit() {
    this.isViewInitialized = true;
    this.updateComponent();  
  }

  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }    
  }
}

@Component({
  selector: 'c1',
  template: `<h2>c1</h2><p>{{info.name}}</p>
            <my-sections [sections]="section"></my-sections>`

})
export class C1 {
}

@Component({
  selector: 'c2',
  template: `<h2>c2</h2><p>{{info.name}}</p>
            <my-sections [sections]="section"></my-sections>`
})
export class C2 {
}

@Component({
  selector: 'c3',
  template: `<h2>c3</h2><p>{{info.name}}</p>
            <my-sections [sections]="section"></my-sections>`

})
export class C3 {
}

@Component({
  selector: 'c4',
  template: `<h2>c4</h2><p>{{info.name}}</p>`

})
export class C4 {
}

@Component({
  selector: 'c5',
  template: `<h2>c5</h2><p>{{info.name}}</p>`

})
export class C5 {
}

@Component({
  selector: 'my-sections',
  directives: [ChildDclWrapper],
  template: `
  <h3>Sections</h3>
  <div *ngFor="let section of type.sections">
    <child-dcl-wrapper [type]="section"></child-dcl-wrapper>
  </div>
`
})
export class Sections {
  @Input() sections;
}

@Component({
  selector: 'my-tabs',
  directives: [DclWrapper],
  template: `
  <h2>Tabs</h2>
  <div *ngFor="let tab of tabs">
    <dcl-wrapper [type]="tab"></dcl-wrapper>
  </div>
`
})
export class Tabs {
  @Input() tabs;
}

@Injectable()
export class AService {
  info = [
    {
      name: "taco",
      type: C1,
      sections: [
        {
          name: "believe",
          type: C4
        },
        {
          name: "car",
          type: C5
        }
      ]
    },
    {
      name: "pete",
      type: C2,
      sections: [
        {
          name: "repeat",
          type: C4
        },
        {
          name: "banana",
          type: C5
        }
      ]
    },
    {
      name: "carl",
      type: C3,
      sections: [
        {
          name: "shotgun",
          type: C4
        },
        {
          name: "helmet",
          type: C5
        }
      ]
    }
  ];

  getServiceInfo() {
    console.log("Bung.");
    return this.info;
  }
}

@Component({
  selector: 'my-app',
  directives: [Tabs],
  providers: [AService],
  template: `
  <h1>Hello {{name}}</h1>
  <my-tabs [tabs]="types"></my-tabs>
`
})
export class App extends OnInit {
  types;
  aService;

  constructor(private aService: AService) {
    this.aService = aService;
  }

  getInfo() {
    console.log("beep");
    this.types = this.aService.getServiceInfo();
  }

  ngOnInit() {
    console.log("boop");
    this.getInfo();
  }
}

I see several errors in your code. 我在您的代码中看到了几个错误。 For example you need to use info.sections instead just section in the following code: 例如,您需要使用info.sections而不是下面的代码中的section

<my-sections [sections]="section"></my-sections>

It should be: 它应该是:

<my-sections [sections]="info.sections"></my-sections>

Also you forgot to add Sections directive like this: 您也忘记添加像这样的Sections指令:

@Component({
  selector: 'c1',
  template: `<h2>c1</h2><p>{{info.name}}</p>
            <my-sections [sections]="info.sections"></my-sections>`,
  directives: [Sections] <== add this line

})
export class C1 {}

And you can use one DclWrapper to do that. 而且,您可以使用一个DclWrapper来做到这一点。

The updated plunkr is here https://plnkr.co/edit/JRyqou9yC6LvSRrCR3eA?p=preview 更新的plunkr在这里https://plnkr.co/edit/JRyqou9yC6LvSRrCR3eA?p=preview

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM