我有一个关于 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>
谢谢!
创建组件时,您可以传递将充当所创建组件的宿主元素的 DOM 节点:
创建(注入器:注入器,projectableNodes?:任何[] [], rootSelectorOrNode?: string|any, ngModule?: NgModuleRef): 组件参考
但是由于该组件不是任何其他组件的子组件,因此您必须手动将其附加到 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);
}
}
永远不要在 Angular 之外修改 DOM,因为这会导致不可预测的行为。即使您手动附加
<simple-cmp>
元素,它也没有任何意义,因为它不是由 Angular 处理的。 Angular 应用程序内对 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);
}
}
看看我在另一个帖子中对与此主题相关的问题的回答,也许对某人有用。