问题
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()">< Back</button></td>
<td style="text-align: right"><button (click)="nextBtnClick()">Next ></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:随意更新示例