Dan*_*lar 5 angular-services angular-components angular
在角度2中创建动态组件时,我发现此过程需要ViewContainerRef才能将新创建的组件添加到DOM.
Angular 2动态选项卡,用户单击所选组件 https://www.lucidchart.com/techblog/2016/07/19/building-angular-2-components-on-the-fly-a-dialog-box-example/
在将输入和输出传递给那些动态创建的组件时,我在上面的第二个链接中找到了答案:https: //codedump.io/share/kQakwDKNu0iG/1/passing-input-while-creating-angular-2-组件的动态使用-componentresolver
但是,如果我要创建一个名为shape.service的服务,其中包含使用bgColor等输入返回不同形状组件的函数,我不知道该服务如何在不指定DOM位置的情况下创建组件,以及容器组件如何接收这个返回的组件(可能是它的类型将是ComponentRef)来自服务并将其注入DOM容器组件指定.
例如,服务包含一个功能:
getCircle(bgColor:string): ComponentRef<Circle> {
let circleFactory = componentFactoryResolver.resolveComponentFactory(CircleComponent);
let circleCompRef = this.viewContainerRef.createComponent(circleFactory);
circleCompRef.instance.bgColor = bgColor;
return circleCompRef;
}
Run Code Online (Sandbox Code Playgroud)
第一个问题在这里提出,我如何ViewContainerRef在此期间指出无处?我导入viewContainerRef的原因是动态创建组件.
第二个问题是容器组件@Input从服务接收特定于输入的内容后,它将如何注入其DOM?
提前致谢!
更新: 我认为上面的问题不够具体.我遇到的情况是:
这意味着服务调用组件不知道这些componentRef将被注入的位置.简而言之,我需要可以随时随地注入的独立组件对象.
我已经好几次读过rumTimeCompiler解决方案,但我真的不知道它是如何工作的.与使用viewContainerRef创建组件相比,似乎有太多工作要做.如果我找不到其他解决方案,我会深入研究一下......
如果像我这样的人现在仍在寻找一个简单而清晰的解决方案 - 就在这里。我从@angular/cdk https://github.com/angular/components/tree/master/src/cdk得到它 并做了一个简单的服务。
import {
Injectable,
ApplicationRef,
ComponentFactoryResolver,
ComponentRef,
Injector,
EmbeddedViewRef
} from '@angular/core';
export type ComponentType<T> = new (...args: any[]) => T;
@Injectable({
providedIn: 'root'
})
export class MyService {
constructor(
private _appRef: ApplicationRef,
private _resolver: ComponentFactoryResolver,
private _injector: Injector
) { }
private _components: ComponentRef<any>[] = [];
add<T>(
component: ComponentType<T> | ComponentRef<T>,
element?: Element | string
): ComponentRef<T> {
const componentRef = component instanceof ComponentRef
? component
: this._resolver.resolveComponentFactory(component).create(this._injector);
this._appRef.attachView(componentRef.hostView);
if (typeof element === 'string') {
element = document.querySelector(element);
}
if (!element) {
element = document.body;
}
element.appendChild(
(componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement
);
this._components.push(componentRef);
return componentRef;
}
remove(dialog: number | ComponentRef<any>): boolean {
let componentRef;
if (typeof dialog === 'number' && this._components.length > dialog) {
componentRef = this._components.splice(dialog, 1)[0];
}
else {
for (const cr of this._components) {
if (cr === dialog) {
componentRef = cr;
}
}
}
if (componentRef) {
this._remove(componentRef);
return true;
}
return false;
}
private _remove(componentRef: ComponentRef<any>) {
this._appRef.detachView(componentRef.hostView);
componentRef.destroy();
}
clear() {
while (this._components.length > 0) {
this._remove(this._components.pop());
}
}
getIndex(componentRef: ComponentRef<any>): number {
return this._components.indexOf(componentRef);
}
}
Run Code Online (Sandbox Code Playgroud)
您可以将 ComponentClass 或 ComponentRef 传递给addand Element 或任何指向任何 DOM 元素的 querySelector 字符串,您希望将组件作为第二个参数附加到其中(或者什么都不做,那么它假定您要附加到正文)。
const cr = this._service.add(MyComponent); // will create MyComponent and attach it to document.body or
const cr = this._service.add(MyComponent, this.someElement); // to attach to Element stored in this.someElement or
const cr = this._service.add(MyComponent, 'body div.my-class > div.my-other-div'); // to search for that element and attach to it
const crIndex = this._service.getIndex(cr);
cr.instance.myInputProperty = 42;
cr.instance.myOutputEmitter.subscribe(
() => {
// do something then for example remove this component
this._service.remove(cr);
}
);
this._service.remove(crIndex); // remove by index or
this._service.remove(cr); // remove by reference or
this._service.clear(); // remove all dynamically created components
Run Code Online (Sandbox Code Playgroud)
PS不要忘记你的动态组件添加到entryComponents: []的@NgModule
也许这个plunker会帮助你:https://plnkr.co/edit/iTG7Ysjuv7oiDozuXwj6?p = preview
据我所知,您需要ViewContainerRef服务内部.但是调用您的服务的组件可以将其添加为参数,如下所示:
(只是一个服务..请参阅plunker完整的工作示例)
import { Injectable, ViewContainerRef, ReflectiveInjector, ComponentFactoryResolver, ComponentRef } from '@angular/core';
import { HelloComponent, HelloModel } from './hello.component';
@Injectable()
export class DynamicCompService {
constructor (private componentFactoryResolver: ComponentFactoryResolver) { }
public createHelloComp (vCref: ViewContainerRef, modelInput: HelloModel): ComponentRef {
let factory = this.componentFactoryResolver.resolveComponentFactory(HelloComponent);
// vCref is needed cause of that injector..
let injector = ReflectiveInjector.fromResolvedProviders([], vCref.parentInjector);
// create component without adding it directly to the DOM
let comp = factory.create(injector);
// add inputs first !! otherwise component/template crashes ..
comp.instance.model = modelInput;
// all inputs set? add it to the DOM ..
vCref.insert(comp.hostView);
return comp;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8427 次 |
| 最近记录: |