从 json 响应创建动态嵌套组件
Creating dynamic nested components from json response
我正在尝试根据 json 响应创建嵌套动态组件。
public content={type:'paragraph',depth:1,text:'Root',entityRanges:[{type:'LINK',offset:83,length:16,data:{target:'_self',url:'/index.htm'}}],embbeded:[{type:'text',text:'This is Text component'}]}
所以在上面的结构中,它是类型paragraph
所以ParagraphComponent
需要先渲染。
它作为一个数组对象embbeded
,我想在这个数组中渲染TextComponent
。
所以最后的输出应该是这样的,
<paraComp><p><textComp>This is Text component</textComp></p></paraComp>
下面是我试过的,
主要成分
export class AppComponent implements OnInit {
@ViewChild('container', { read: ViewContainerRef })
public target: ViewContainerRef;
public content = { type: 'paragraph', depth: 1, text: 'Root', entityRanges: [{ type: 'LINK', offset: 83, length: 16, data: { target: '_self', url: '/index.htm' } }], embbeded: [{ type: 'text', text: 'This is Text component' }] }
constructor(private createDynamicComponentService: CreateDynamicComponentService) { }
ngOnInit() {
this.createDynamicComponentService.createComponent(this.content, this.target);
}
}
主要HTML
<ng-container #container></ng-container>
createDynamicComponentService
export class CreateDynamicComponentService {
private rootViewContainer: ViewContainerRef;
private componentFactory: ComponentFactory<any>;
private componentReference;
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
@Inject(CONTENT_MAPPINGS) private contentMappings: any
) { }
setRootViewContainerRef(view: ViewContainerRef): void {
this.rootViewContainer = view;
}
createComponent(content: any, container: ViewContainerRef) {
const type = this.contentMappings[content.type];
console.log(type);
this.componentFactory = this.componentFactoryResolver.resolveComponentFactory(type);
this.componentReference = this.rootViewContainer.createComponent(this.componentFactory);
this.componentReference.instance.contentOnCreate(content);
}
}
Link 到项目 https://stackblitz.com/edit/angular-dynamic-new?file=src/app/app.component.ts
仅基于它我创建了我的项目。但是无法让它工作。
请帮忙。
执行此操作的最简单方法可能如下所示:
@Injectable()
export class CreateDynamicComponentService {
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
@Inject(CONTENT_MAPPINGS) private contentMappings: any
) { }
createComponent(content: any, container: ViewContainerRef) {
const type = this.contentMappings[content.type];
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(type);
const componentRef = container.createComponent<any>(componentFactory);
if (componentRef.instance.contentOnCreate) {
componentRef.instance.contentOnCreate(content);
}
if (!content.embedded) return;
// render children recursively
for (const embeddedContent of content.embedded) {
// in order to render children component must define ViewContainerRef
if (!componentRef.instance.embeddedContainer) {
const cmpName = componentRef.instance.constructor.name;
throw new TypeError(`Trying to render embedded content.
${cmpName} must have @ViewChild() embeddedContainer defined`);
}
this.createComponent(embeddedContent, componentRef.instance.embeddedContainer);
}
}
}
为了呈现子组件,组件应该定义将呈现子组件的容器,例如:
paragraph.component.html
<p>
<ng-container #embeddedContainer></ng-container>
</p>
paragraph.component.ts
export class ParagraphComponent implements OnInit {
@ViewChild('embeddedContainer', { read: ViewContainerRef }) embeddedContainer: ViewContainerRef;
我正在尝试根据 json 响应创建嵌套动态组件。
public content={type:'paragraph',depth:1,text:'Root',entityRanges:[{type:'LINK',offset:83,length:16,data:{target:'_self',url:'/index.htm'}}],embbeded:[{type:'text',text:'This is Text component'}]}
所以在上面的结构中,它是类型paragraph
所以ParagraphComponent
需要先渲染。
它作为一个数组对象embbeded
,我想在这个数组中渲染TextComponent
。
所以最后的输出应该是这样的,
<paraComp><p><textComp>This is Text component</textComp></p></paraComp>
下面是我试过的,
主要成分
export class AppComponent implements OnInit {
@ViewChild('container', { read: ViewContainerRef })
public target: ViewContainerRef;
public content = { type: 'paragraph', depth: 1, text: 'Root', entityRanges: [{ type: 'LINK', offset: 83, length: 16, data: { target: '_self', url: '/index.htm' } }], embbeded: [{ type: 'text', text: 'This is Text component' }] }
constructor(private createDynamicComponentService: CreateDynamicComponentService) { }
ngOnInit() {
this.createDynamicComponentService.createComponent(this.content, this.target);
}
}
主要HTML
<ng-container #container></ng-container>
createDynamicComponentService
export class CreateDynamicComponentService {
private rootViewContainer: ViewContainerRef;
private componentFactory: ComponentFactory<any>;
private componentReference;
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
@Inject(CONTENT_MAPPINGS) private contentMappings: any
) { }
setRootViewContainerRef(view: ViewContainerRef): void {
this.rootViewContainer = view;
}
createComponent(content: any, container: ViewContainerRef) {
const type = this.contentMappings[content.type];
console.log(type);
this.componentFactory = this.componentFactoryResolver.resolveComponentFactory(type);
this.componentReference = this.rootViewContainer.createComponent(this.componentFactory);
this.componentReference.instance.contentOnCreate(content);
}
}
Link 到项目 https://stackblitz.com/edit/angular-dynamic-new?file=src/app/app.component.ts
仅基于它我创建了我的项目。但是无法让它工作。
请帮忙。
执行此操作的最简单方法可能如下所示:
@Injectable()
export class CreateDynamicComponentService {
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
@Inject(CONTENT_MAPPINGS) private contentMappings: any
) { }
createComponent(content: any, container: ViewContainerRef) {
const type = this.contentMappings[content.type];
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(type);
const componentRef = container.createComponent<any>(componentFactory);
if (componentRef.instance.contentOnCreate) {
componentRef.instance.contentOnCreate(content);
}
if (!content.embedded) return;
// render children recursively
for (const embeddedContent of content.embedded) {
// in order to render children component must define ViewContainerRef
if (!componentRef.instance.embeddedContainer) {
const cmpName = componentRef.instance.constructor.name;
throw new TypeError(`Trying to render embedded content.
${cmpName} must have @ViewChild() embeddedContainer defined`);
}
this.createComponent(embeddedContent, componentRef.instance.embeddedContainer);
}
}
}
为了呈现子组件,组件应该定义将呈现子组件的容器,例如:
paragraph.component.html
<p>
<ng-container #embeddedContainer></ng-container>
</p>
paragraph.component.ts
export class ParagraphComponent implements OnInit {
@ViewChild('embeddedContainer', { read: ViewContainerRef }) embeddedContainer: ViewContainerRef;