typescript Angular 2 在不使用 ViewContainerRef 的情况下将组件动态插入到特定的 DOM 节点
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39357195/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Angular 2 Dynamically insert a component into a specific DOM node without using ViewContainerRef
提问by Valikhan Akhmedov
I have a question regarding dynamic component creation in Angular 2 rc5.
我有一个关于在 Angular 2 rc5 中创建动态组件的问题。
So let's assume that we have two plain angular components:
所以让我们假设我们有两个普通的角度分量:
@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!' }
Then some external non-angular chunck of code modificates a DOM:
然后一些外部非角度代码块修改了 DOM:
let newNode = document.createElement('div');
newNode.id = 'placeholder';
document.getElementById('container').appendChild(newNode);
Here is some presumable tree after manipulations:
这是操作后的一些可能的树:
<div id="container">
<h1>My Component</h1>
<div id="placeholder"></div>
</div>
So what I'm trying to do is just dynamically add SimpleComoponent instance into #placeholder div. How can I achieve this result?
所以我想要做的只是将 SimpleComoponent 实例动态添加到 #placeholder div 中。我怎样才能达到这个结果?
I've been trying using ComponentFactory.createComponent(injector, [], newNode), it added the component though, but neither life cycle hooks nor binding not worked at all.
我一直在尝试使用 ComponentFactory.createComponent(injector, [], newNode),虽然它添加了组件,但生命周期钩子和绑定都不起作用。
I believe there is some way to implement this using ViewContainerRef, but how can I link it with dynamically created node?
我相信有一些方法可以使用 ViewContainerRef 来实现这一点,但是如何将它与动态创建的节点链接起来?
Here is the result I expect
这是我期望的结果
<div id="container">
<h1>My Component</h1>
<div id="placeholder">
<simple-cmp>Hello world!</simple-cmp>
</div>
</div>
Thanks!
谢谢!
回答by Max Koretskyi
When creating a componentyou can pass the DOM node that will act as a host element of the created component:
创建组件时,您可以传递将充当所创建组件的宿主元素的 DOM 节点:
create(injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string|any, ngModule?: NgModuleRef): ComponentRef
create(injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string|any, ngModule?: NgModuleRef): ComponentRef
But since this component is not child of any other component, you have to manually attach it to ApplicationRef so you get change detection.
但是由于该组件不是任何其他组件的子组件,因此您必须手动将其附加到 ApplicationRef 以便进行更改检测。
So here is what you need to do:
所以这是你需要做的:
1) Create a component specifying the root node under which it should be added.
2) Attach the view to the ApplicationRef so that you get change detection. You will still have no Input
and ngOnChanges
operations, but the DOM update will be working fine.
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);
}
}
回答by martin
You should never modify DOM outside Angular because it will lead to unpredictable behavior. Even if you append <simple-cmp>
element manually it means nothing because it's not processed by Angular. All changes to DOM inside Angular app have to go through Angular methods.
你永远不应该在 Angular 之外修改 DOM,因为它会导致不可预测的行为。即使您<simple-cmp>
手动附加元素也没有任何意义,因为它不是由 Angular 处理的。Angular 应用程序中对 DOM 的所有更改都必须通过 Angular 方法。
Dynamically create a new component:
动态创建一个新组件:
@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);
}
}