我有一个AppComponent
,其中包含ShapeComponents
的列表。我实现了一些扩展ShapeComponent
的组件,例如LineComponent
,CircleComponent
,RectangleComponent
。他们每个人都有自己的ng-template
和#shapeTemplate
。
在我的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会很有用,但不知道如何处理
答案 0 :(得分:1)
有一种显示组件的解决方案,但这很复杂,不是我的建议。
针对您的问题的“角度样式”解决方案是这样的:
models
。typeOf
)。让我们打电话给shape
。如果愿意,还可以使用枚举。ngFor
中的模型,并为每个模型创建一个组件。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。
答案 1 :(得分:1)
最近我做了类似的事情。这是最后的stackblitz
首先,我创建一个ShapeComponent
file1=$(cat dir.txt)
echo $file1
它的模板有一个test-dir
,以便我们可以引用它,还有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>;
}
一起列出。由于每个ShapeComponent
都提供了自己的名称,因此我们可以获得它们的列表并使用它们的ContentChildren
。
最后,让我们在ShapeComponent
template
输出为
AppComponent
答案 2 :(得分:0)
在这种情况下,最好也是官方建议的方法是使用Dynamic Forms。
在文档中,您会找到一些有用的提示
答案 3 :(得分:0)
我找到了解决方案。实际上,我在github上找到了一个很棒的帖子
https://github.com/shivs25/angular5-canvas-drawer。我采用了这种解决方案来实现自己的解决方案。
因此所有功劳归Billy Shivers所有。干得好。
这是解决方案
直线和圆的设置可以动态设置,下面仅是直线和圆的示例
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
}
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,为svg在CSS中设置宽度的高度
<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>
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 { }
还有我的应用的最终屏幕截图
我希望这个答案有用,并且可以在您自己的应用中使用。这个想法是创建动态模板视图