Angular2:创建Component的实例而不注入它

时间:2016-05-19 14:06:11

标签: angular components

问题

Angular2中是否有一种方法可以在不实际注入的情况下创建Component的实例?使用ViewContainerRef.insert()或类似的其他地方将组件插入到视图中。

我知道有DynamicComponentLoader,但它需要一个ViewContainerRef来附加它自己创建的实例。那时候的观点根本不存在。

问题是,我想创建视图实例,配置它们(甚至通过自定义工厂)并将它们添加到任何其他点的任何视图。

有ViewContainerRef,它能够在任意索引处插入一个ViewRef,这个目前还不错,但是如何从我创建的Component创建一个ViewRef,而不是实际插入它?

我希望你能得到我的问题:P

更新

示例应用程序可以是通过表单导航的轮播。视图应该被创建,只有当前索引的视图应该加载它之前的状态。

这是一个未完成的示例,其中包含一些标记关键位置的TODO(请参阅loadViews()和showView()以获取想法)。

import {Component, ViewChild, ViewContainerRef, AfterViewInit} from '@angular/core'

export interface Storable {
  save(transaction: any): void; //transaction is usually a defined type, but this would go too far for this example
}

@Component({
  selector: 'user-form',
  template: `<div>
   User name: <input type="text" [(ngModel)]="uname" /><br />
   Password: <input type="password" [(ngModel)]="passwd" />
  </div>`
})
export class UserForm implements Storable {
  public uname: string = null;
  public passwd: string = null;

  constructor() {

  }

  public save(transaction: any): void {
    //save this.uname via transaction (not important for this example)
    //save this.passwd via transaction (not important for this example)
  }
}

@Component({
  selector: 'address-form',
  template: `<div>
   Street: <input type="text" [(ngModel)]="street" /><br />
   City: <input type="password" [(ngModel)]="city" /><br />
   Postal Code: <input type="password" [(ngModel)]="postalCode" />
  </div>`
})
export class AddressForm implements Storable {
  public street: string = null;
  public city: string = null;
  public postalCode: string = null;

  constructor() {

  }

  public save(transaction: any): void {
    //save this.street via transaction (not important for this example)
    //save this.city via transaction (not important for this example)
    //save this.postalCode via transaction (not important for this example)
  }
}

@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <div>
      <h2>Carousel/Wizzard like state maintaining navigation</h2>
      <table style="width: 100%">
        <tr>
          <td style="text-align: left"><button (click)="prevBtnClick()">&lt; Back</button></td>
          <td style="text-align: right"><button (click)="nextBtnClick()">Next &gt;</button></td>
        </tr>
        <tr>
          <td colspan="2" style="text-align: center" #content>
            <!-- here goes the content -->
            <p *ngIf="ci < 0">No content loaded</p>
          </td>
        </tr>
      </table>
    </div>
  `,
  directives: []
})
export class App implements AfterViewInit {
  @ViewChild('content', {read: ViewContainerRef}) content: ViewContainerRef;

  private ci = -1;
  private views = [];

  constructor() {
    this.loadViews();

    if(this.views.length > 0) {
      this.ci = 0;
    }
  }

  public ngAfterViewInit(): void {
    this.showView(this.ci);
  }

  //THIS IS THE KEY PART Nr. 1
  public loadViews(): void { //this is simplyfied, in my case this is happening via a config loader which returns an array of "INITIALIZED" views
    //i know that this does not work! It is just to get the idea:
    var v = new UserForm();
    v.uname = "Some initialized value";
    v.passwd = "Usually loaded by another instance";
    this.views.push(v);

    v = new AddressForm();
    v.street = "Examplestreet 15";
    v.city = "Exampletown";
    v.postalCode = "12345";
    this.views.push(v);
  }

  protected prevBtnClick(): void {
    if(this.ci < 0)
      return;

    this.ci++;

    if(this.ci >= this.views.length)
      this.ci = 0;

    this.showView(this.ci);
  }

  protected nextBtnClick(): void {
    if(this.ci < 0)
      return;

    this.ci--;

    if(this.ci < 0)
      this.ci = this.views.length - 1;

    this.showView(this.ci);
  }

  //THIS IS THE KEY PART Nr. 2
  public showView(index: number): void {
    if(index < 0 || index >= this.views.length || !this.views || this.views.length == 0)
      return;

    this.ci = index;

    var view = this.views[index];

    //TODO: remove the currently loaded view from this.content
    //TODO: load the view instance in this.content without creating a new instance
    //      because the state of the instance must be maintained!!
  }

  //not important for this example
  public save(transaction: any): void {
    for(var v of this.views)
      (<Storable><any>v).save(transaction);
  }
}

In Plunkr:随意更新示例

0 个答案:

没有答案