问题描述
我的目标是创建一个子组件并插入到父组件模板中.有一些例子可以做到这一点.但是,我在父组件中动态创建父组件模板(DOM 元素),而显示的大多数示例静态创建带有捕获元素的模板.
这是代码
应用程序组件
import {Component, ViewChild, ViewContainerRef, ComponentFactoryResolver} from '@angular/core';从./newChild.component"导入{NewChildComponent};@成分({选择器:'app-main',templateUrl: 'app.component.html'})导出类 AppComponent {@ViewChild('captureElement', {读取:ViewContainerRef})捕获元素:ViewContainerRef;构造函数(私有 componentFactoryResolver:ComponentFactoryResolver){var childComponent = this.componentFactoryResolver.resolveComponentFactory(NewChildComponent);var myArea = document.getElementById('myArea');var myRow = document.createElement("div");myArea.appendChild(myRow);//我想添加捕获元素#myCapture作为myRow的子元素//添加类似这样的通过 JS/TS 以编程方式//我怎样才能做到这一点?//然后我创建组件this.parent.createComponent(NewChildComponent);}
app.component.html
<!-- 静态方法--><!--<div #captureElement></div>-->
我不想在 #captureElement
中静态定义插入子组件的位置,而是想在父组件中动态创建它并使其成为子组件.
这是我在问这个问题之前提到的问题列表
尝试了一些东西
- 尝试创建一个
div
元素,并将#captureElement
作为以编程方式属性,但这不起作用. - 尝试以编程方式创建一个随机元素并使用
ViewContainerRef
找到它.这也行不通.
我们不能创建 ViewContainerRef
,因为 ViewContainerRef
只存在于视图中.>
在 2.3.0 中,引入了 attachView
,它允许您将更改检测附加到 ApplicationRef.您可以创建一些类来封装您的逻辑,例如:
导出类 HtmlContainer {私人附加:boolean = false;私有 disposeFn: () =>空白;构造函数(私有主机元素:元素,私有 appRef: ApplicationRef,私有 componentFactoryResolver: ComponentFactoryResolver,私人注射器:注射器){}attach(component: Type) : ComponentRef{如果(这个.附加){throw new Error('组件已经被附加')}this.attached = true;const childComponentFactory = this.componentFactoryResolver.resolveComponentFactory(component);让 componentRef = childComponentFactory.create(this.injector);this.appRef.attachView(componentRef.hostView);this.disposeFn = () =>{this.appRef.detachView(componentRef.hostView);componentRef.destroy();};this.hostElement.appendChild((componentRef.hostView as EmbeddedViewRef).rootNodes[0]);返回组件引用;}处置(){如果(这个.附加){this.disposeFn();}}}
这个类只是帮手
1) 解析您的动态组件
this.componentFactoryResolver.resolveComponentFactory(component);
2) 然后通过调用 compFactory.create
3) 然后通过调用上面提到的 appRef.attachView
注册它的 changeDetector
(componentRef.hostView
extends ChangeDetectorRef
)代码>(否则更改检测将不适用于您的组件)
4) 最后将组件的 rootNode 附加到宿主元素
this.hostElement.appendChild((componentRef.hostView as EmbeddedViewRef).rootNodes[0]);
您可以按如下方式使用它:
@Component({选择器:'我的应用',模板:`<div id="myArea"></div>`,entryComponents: [NewChildComponent]})导出类 AppComponent {容器:HtmlContainer[] = [];构造函数(私有 appRef: ApplicationRef,私有 componentFactoryResolver: ComponentFactoryResolver,私人注射器:注射器){}ngOnInit() {var myArea = document.getElementById('myArea');var myRow = document.createElement("div");myArea.appendChild(myRow);this.addComponentToRow(NewChildComponent, myRow, 'test1');this.addComponentToRow(NewChildComponent, myRow, 'test2');}addComponentToRow(component: Type, row: HTMLElement, param: string) {let container = new HtmlContainer(row, this.appRef, this.componentFactoryResolver, this.injector);让 componentRef = container.attach(component);componentRef.instance.param1 = param;this.containers.push(container);}ngOnDestroy() {this.containers.forEach(container => container.dispose());}}
另见
- Angular2 - 组件到动态创建的元素
- 根中的Angular2动态组件注入
- https://github.com/angular/material2/blob/2.0.0-beta.1/src/lib/core/portal/dom-portal-host.ts#L30-L86(您可以在此处找到 angular
My goal is to create a child component and insert into the parent component template. There are examples to do this. However, I create parent component template (DOM Elements) dynamically in the parent component while most of the examples shown statically create the template with the capture element.
Here's the code
app.component
import {Component, ViewChild, ViewContainerRef, ComponentFactoryResolver} from '@angular/core';
import {NewChildComponent} from "./newChild.component";
@Component({
selector: 'app-main',
templateUrl: 'app.component.html'
})
export class AppComponent {
@ViewChild('captureElement', {read: ViewContainerRef})
captureElement: ViewContainerRef;
constructor (private componentFactoryResolver: ComponentFactoryResolver) {
var childComponent = this.componentFactoryResolver.resolveComponentFactory(NewChildComponent);
var myArea = document.getElementById('myArea');
var myRow = document.createElement("div");
myArea.appendChild(myRow);
//I want to add the capture element #myCapture as a child of myRow
//Add something like this <div #captureElement></div> programmatically through JS/TS
// How can I do this?
// I then create the component
this.parent.createComponent(NewChildComponent);
}
app.component.html
<div id="myArea">
<!-- Static way of doing it -->
<!--<div #captureElement></div>-->
</div>
Instead of statically defining in #captureElement
where the child component would be inserted, I would like to create it dynamically in the parent component and make it a child component.
Here are a list of questions I referred before I asked this question
- Angular2: Insert a dynamic component as child of a container in the DOM
- How to place a dynamic component in a container
- Angular 2 dynamic tabs with user-click chosen components
Tried a couple of things
- Tried to create a
div
element with a#captureElement
as anattribute programmatically but that doesn't work. - Tried to create a random element programmatically and use
ViewContainerRef
to find it. That doesn't work either.
We can't create a ViewContainerRef
, as a ViewContainerRef
only exists within a view.
In 2.3.0, attachView
was introduced which allows you to be able to attach change detection to the ApplicationRef. You can create some class that will encapsulate your logic like:
export class HtmlContainer {
private attached: boolean = false;
private disposeFn: () => void;
constructor(
private hostElement: Element,
private appRef: ApplicationRef,
private componentFactoryResolver: ComponentFactoryResolver,
private injector: Injector) {
}
attach(component: Type<any>) : ComponentRef<any> {
if(this.attached) {
throw new Error('component has already been attached')
}
this.attached = true;
const childComponentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
let componentRef = childComponentFactory.create(this.injector);
this.appRef.attachView(componentRef.hostView);
this.disposeFn = () => {
this.appRef.detachView(componentRef.hostView);
componentRef.destroy();
};
this.hostElement.appendChild((componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0]);
return componentRef;
}
dispose() {
if(this.attached) {
this.disposeFn();
}
}
}
this class is just helper that
1) resolves your dynamic component
this.componentFactoryResolver.resolveComponentFactory(component);
2) then compiles component by calling compFactory.create
3) after that registers its changeDetector
(componentRef.hostView
extends ChangeDetectorRef
) by calling mentioned above appRef.attachView
(otherwise change detection won't work for your component)
4) and finally appends the rootNode of your component to the host element
this.hostElement.appendChild((componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0]);
You can use it as follows:
@Component({
selector: 'my-app',
template: `<div id="myArea"></div> `,
entryComponents: [NewChildComponent]
})
export class AppComponent {
containers: HtmlContainer[] = [];
constructor(
private appRef: ApplicationRef,
private componentFactoryResolver: ComponentFactoryResolver,
private injector: Injector) {
}
ngOnInit() {
var myArea = document.getElementById('myArea');
var myRow = document.createElement("div");
myArea.appendChild(myRow);
this.addComponentToRow(NewChildComponent, myRow, 'test1');
this.addComponentToRow(NewChildComponent, myRow, 'test2');
}
addComponentToRow(component: Type<any>, row: HTMLElement, param: string) {
let container = new HtmlContainer(row, this.appRef, this.componentFactoryResolver, this.injector);
let componentRef = container.attach(component);
componentRef.instance.param1 = param;
this.containers.push(container);
}
ngOnDestroy() {
this.containers.forEach(container => container.dispose());
}
}
See also
- Angular2 - Component into dynamicaly created element
- Angular2 Dynamic Component Injection in Root
- https://github.com/angular/material2/blob/2.0.0-beta.1/src/lib/core/portal/dom-portal-host.ts#L30-L86 (you can find here fallback for angular < 2.3.0)
这篇关于Angular 2:创建组件时动态插入捕获元素(动态)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!