我有一个包含ShapeComponents列表的AppComponent。我实现了一些扩展ShapeComponent的组件,如LineComponent、CircleComponent、RectangleComponent。它们中的每一个都有自己的#shapeTemplate ng-template。在我的app.component.html中,我想遍历ShapeComponents列表并显示每个ng-template (来自LineComponent、CircleComponent等)。
所以我有
shapes: ShapeComponent[] = []其中包含LineComponent、CircleComponent等
我想要这样的东西
<div *ngFor="let shape of shapes">
<!-- How to display the ng-template from for example LineComponent or Circle -->
</div>我认为使用@ViewChildren或@ContentChildren会很有用,但不知道如何处理
发布于 2018-09-18 15:49:07
我最近也做了类似的事情。这是最终的stackblitz
首先,我创建了一个ShapeComponent
import {
Component,
Input,
ViewChild,
TemplateRef
} from '@angular/core';
@Component({
selector: 'shape',
template: `<ng-template><ng-content></ng-content></ng-template>`,
})
export class ShapeComponent {
@ViewChild(TemplateRef) template: TemplateRef<any>;
}它的模板有一个ng-template,这样我们就可以引用它,还有一个ng-content,所以这个组件的使用者可以在其中投射他们的内容。
使用@ViewChild(TemplateRef),您可以获得ng-template的引用以及它内部的任何内容,这都是因为ng-content。
让我们创建一个LineComponent
@Component({
selector: 'line',
template: `<ng-template>
This is line and its content: <ng-content></ng-content>
</ng-template>`,
providers: [{
provide: ShapeComponent,
useExisting: forwardRef(() => LineComponent)
}]
})
export class LineComponent extends ShapeComponent {}和CircleComponent
@Component({
selector: 'circle',
template: `<ng-template>
This is circle and its content: <ng-content></ng-content>
</ng-template>`,
providers: [{
provide: ShapeComponent,
useExisting: forwardRef(() => CircleComponent)
}]
})
export class CircleComponent extends ShapeComponent {}这两个组件都扩展了ShapeComponent,并根据自己的需要提供它。因此,每当有人尝试注入ShapeComponent时,他们都会得到一个LineComponent或ShapeComponent。
最后,让我们创建一个ShapeHolderComponent,它将所有这些结合在一起
@Component({
selector: 'shape-holder',
template: `
<div *ngFor="let child of children">
<ng-container *ngTemplateOutlet="child.template"></ng-container>
</div>
`,
})
export class ShapeHolderComponent {
@ContentChildren(ShapeComponent) children: QueryList<ShapeComponent>;
} 您可以使用ContentChildren列出ShapeComponent。因为每个ShapeComponent都提供了自己,所以我们可以获得它们的列表并使用它们的template。
最后,让我们在AppComponent中使用所有这些
<shape-holder>
<circle>
Custom Circle content
</circle>
<line>
Custom Line content
</line>
</shape-holder>输出为
This is circle and its content: Custom Circle content
This is line and its content: Custom Line content发布于 2018-09-18 13:59:44
有一个显示组件的解决方案,但它相当复杂,不是我的建议。
针对您的问题的"angular-style“解决方案是:
models。typeOf)。让我们调用if shape。如果在ngFor中对模型执行prefer.HTML模板可能如下所示
<div *ngFor="let model of models">
<!-- display the ng-template from for example LineComponent or Circle -->
<line [model]="model" *ngIf="model.shape === 'Line'"></line>
<circle [model]="model" *ngIf="model.shape === 'Circle'"></circle>
</div>请参阅完整的工作示例on stackblitz。
发布于 2018-09-19 17:59:11
我找到了解决方案。实际上,我在github上发现了一篇很棒的文章
https://github.com/shivs25/angular5-canvas-drawer。我采用这个解决方案来实现我自己的解决方案。
所以所有的功劳都归了比利·希弗斯。9~10成熟。
以下是解决方案
直线和圆的设置可以动态设置,下面只是直线和圆的一个例子
CircleComponent和HTML模板
import { Component } from '@angular/core';
import { ShapeComponent } from '../shape/shape.component';
@Component({
selector: 'app-circle',
templateUrl: './circle.component.html',
styleUrls: ['./circle.component.css']
})
export class CircleComponent extends ShapeComponent {
constructor() {
super('circle');
}
}html
<ng-template #elementTemplate>
<svg:circle [attr.cx]="50" [attr.cy]="50" [attr.r]="40" stroke="black" stroke-width="3" fill="red" />
</ng-template>>LineComponent和HTML模板
import { Component } from '@angular/core';
import { ShapeComponent } from '../shape/shape.component';
@Component({
selector: 'app-line',
templateUrl: './line.component.html',
styleUrls: ['./line.component.css']
})
export class LineComponent extends ShapeComponent {
constructor() {
super('line');
console.log('linecomponent:constructor');
}
}html
<ng-template #elementTemplate>
<svg:line [attr.x1]="100" [attr.y1]="100" [attr.x2]="200" [attr.y2]="200" style="stroke:#006600; stroke-width:1px" />
</ng-template>>ShapeComponent和HTML
import { Component, OnInit, ViewChild, TemplateRef, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-shape',
templateUrl: './shape.component.html',
styleUrls: ['./shape.component.css']
})
export class ShapeComponent implements OnInit, AfterViewInit {
shapeType: string;
visible: boolean = true;
id: string = 'unknown';
@ViewChild('elementTemplate')
elementTemplate: TemplateRef<any>;
constructor(shapeType: string) {
console.log('shapecomponent constructor :', shapeType);
this.shapeType = shapeType;
}
setid(value: string): void {
this.id = value;
}
ngOnInit() {
console.log('ShapeComponent ngOnInit()');
}
ngAfterViewInit(): void {
console.log('!!!!!!!!! ShapeComponent ngAfterViewInit: ', this.elementTemplate);
}
}html :无
组件类型的枚举
export enum ShapeTypes {
Line,
Circle,
Rectangle
}The ShapeHolderComponent
import { Component, OnInit, ViewChild, TemplateRef, AfterViewInit } from '@angular/core';
import { ShapeComponent } from '../shape/shape.component';
import { LineComponent } from '../line/line.component';
import { CircleComponent } from '../circle/circle.component';
import { ShapeTypes } from '../model/shape-types';
@Component({
selector: 'app-shapeholder',
templateUrl: './shapeholder.component.html',
styleUrls: ['./shapeholder.component.css']
})
export class ShapeholderComponent implements OnInit, AfterViewInit {
@ViewChild('elementTemplate')
elementTemplate: TemplateRef<any>;
shapes: ShapeTypes[];
constructor() {
this.shapes = [];
this.shapes.push(ShapeTypes.Line);
this.shapes.push(ShapeTypes.Circle);
console.log('shapeholder shapes :', this.shapes);
}
ngOnInit() {
console.log('ShapeHolderComponent : ngOnInit()');
}
ngAfterViewInit(): void {
console.log('!!!!!!!!! ShapeHolder ngAfterViewInit: ', this.elementTemplate);
}
}html,在css中设置svg的宽度高度
<svg>
<ng-container *ngFor="let shape of shapes; let i = index">
<ng-container svg-dynamic [componentData]="shape">
</ng-container>
</ng-container>
</svg>其中最重要的部分就是指令
import { Directive, Input, ViewContainerRef, Injector, ComponentFactoryResolver } from '@angular/core';
import { ShapeComponent } from './shape/shape.component';
import { LineComponent } from './line/line.component';
import { CircleComponent } from './circle/circle.component';
import { ShapeTypes } from './model/shape-types';
@Directive({
selector: '[svg-dynamic]'
})
export class SvgDynamicDirective {
constructor(private _viewContainerRef: ViewContainerRef, private _resolver: ComponentFactoryResolver) {
}
@Input() set componentData(data: ShapeTypes) {
console.log('set componentdata : ', data);
let injector = Injector.create([], this._viewContainerRef.parentInjector);
console.log('injector:', injector);
let factory = this._resolver.resolveComponentFactory(this.buildComponent(data));
console.log('factory:', factory);
let component = factory.create(injector);
console.log('component:', component);
let c: ShapeComponent = <ShapeComponent>component.instance;
console.log('viewContainerRef:', this._viewContainerRef);
console.log('elementTemplate:', c.elementTemplate);
this._viewContainerRef.clear();
this._viewContainerRef.createEmbeddedView(c.elementTemplate);
}
private buildComponent(data: ShapeTypes): any {
switch (data) {
case ShapeTypes.Line:
return LineComponent;
case ShapeTypes.Circle:
return CircleComponent;
}
return null;
}
}和app.component html
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<app-shapeholder></app-shapeholder>
</div>The app.component
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'demo1';
}和app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { ShapeComponent } from './shape/shape.component';
import { LineComponent } from './line/line.component';
import { ShapeholderComponent } from './shapeholder/shapeholder.component';
import { SvgDynamicDirective } from './svg-dynamic.directive';
import { CircleComponent } from './circle/circle.component';
@NgModule({
entryComponents: [
LineComponent,
ShapeComponent,
CircleComponent
],
declarations: [
AppComponent,
LineComponent,
ShapeComponent,
CircleComponent,
ShapeholderComponent,
SvgDynamicDirective,
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }以及我的应用程序的最终屏幕截图

我希望你发现这个答案很有用,并且可以在你自己的应用中使用它。其思想是创建动态模板视图
https://stackoverflow.com/questions/52379006
复制相似问题