我对Angular 2 rc5中的动态组件创建有疑问。
因此我们假设我们有两个普通的角度分量:
@Component({
template: `
<div id="container">
<h1>My Component</h1>
</div>
`,
selector: 'my-app'
})
export class AppComponent { }
@Component({
template: '<p>{{text}}</p>',
selector: 'simple-cmp'
})
export class SimpleComponent { public text='Hello World!' }
然后一些外部非角度代码块修改DOM:
let newNode = document.createElement('div');
newNode.id = 'placeholder';
document.getElementById('container').appendChild(newNode);
这是操作后的一些可能的树:
<div id="container">
<h1>My Component</h1>
<div id="placeholder"></div>
</div>
所以我要做的就是将SimpleComoponent实例动态添加到#placeholder div中。我怎样才能达到这个效果?
我一直在尝试使用ComponentFactory.createComponent(injector,[],newNode),虽然它添加了组件,但生命周期钩子和绑定都没有工作。
我相信有一些方法可以使用ViewContainerRef来实现它,但是如何将它与动态创建的节点链接?
这是我期望的结果
<div id="container">
<h1>My Component</h1>
<div id="placeholder">
<simple-cmp>Hello world!</simple-cmp>
</div>
</div>
谢谢!
答案 0 :(得分:14)
When creating a component您可以传递将充当所创建组件的主机元素的DOM节点:
create(injector:Injector,projectableNodes?:any [] [], rootSelectorOrNode?:string | any ,ngModule?:NgModuleRef): ComponentRef
但由于此组件不是任何其他组件的子组件,因此您必须手动将其附加到ApplicationRef,以便进行更改检测。
所以这就是你需要做的事情:
1)创建一个组件,指定应添加它的根节点
2)将视图附加到ApplicationRef,以便进行更改检测。您仍然没有Input
和ngOnChanges
操作,但DOM更新工作正常。
@Component({
template: `
<div id="container">
<h1>My Component</h1>
</div>
`,
selector: 'my-app'
})
export class AppComponent {
constructor(private resolver: ComponentFactoryResolver,
private injector: Injector,
private app: ApplicationRef) {
}
addDynamicComponent() {
let factory = this.resolver.resolveComponentFactory(SimpleComponent);
let newNode = document.createElement('div');
newNode.id = 'placeholder';
document.getElementById('container').appendChild(newNode);
const ref = factory.create(this.injector, [], newNode);
this.app.attachView(ref.hostView);
}
}
答案 1 :(得分:7)
你永远不应该在Angular之外修改DOM,因为它会导致不可预测的行为。即使您手动附加<simple-cmp>
元素,它也没有任何意义,因为它没有被Angular处理。 Angular app中对DOM的所有更改都必须通过Angular方法。
动态创建新组件:
@Component({
selector: 'my-component',
template: '<div #element></div>',
})
export class MyComponent {
@ViewChild('element', {read: ViewContainerRef}) private anchor: ViewContainerRef;
constructor(private resolver: ComponentFactoryResolver) { }
whatever() {
let factory = this.resolver.resolveComponentFactory(ChildComponent);
this.anchor.createComponent(factory);
}
}