如何从列表显示ng-templates [英] How to display ng-templates from list
问题描述
我有一个AppComponent
,其中保存着ShapeComponents
的列表.我实现了一些扩展ShapeComponent
的组件,例如LineComponent
,CircleComponent
,RectangleComponent
.它们每个都有自己的ng-template
和#shapeTemplate
.
在我的app.component.html
中,我想遍历ShapeComponents
的列表并显示每个ng-template
(来自LineComponent
,CircleComponent
等).
I have an AppComponent
which holds a list of ShapeComponents
. I implemented some Components which extends the ShapeComponent
like LineComponent
, CircleComponent
, RectangleComponent
. Each of them has its own ng-template
with #shapeTemplate
.
In my app.component.html
I want to iterate over the list of ShapeComponents
and display each ng-template
(from LineComponent
, CircleComponent
etc).
所以我有
shapes: ShapeComponent[] = []
其中包含LineComponent,CircleComponent等
which hold a LineComponent, CircleComponent etc
我想要这样的东西
<div *ngFor="let shape of shapes">
<!-- How to display the ng-template from for example LineComponent or Circle -->
</div>
我认为使用@ViewChildren或@ContentChildren会很有用,但不知道如何处理
I thought using @ViewChildren or @ContentChildren would be useful but no idea how to deal with that
推荐答案
我找到了解决方案.实际上,我在github上找到了一个很棒的帖子
I found the solution. Actually I found an excellent post on github
https://github.com/shivs25/angular5-canvas-drawer .我采用了这种解决方案来实现自己的解决方案.
https://github.com/shivs25/angular5-canvas-drawer. I took this solution to implement my own.
因此,所有功劳归Billy Shivers所有.干得好.
So all the credits go to Billy Shivers. Well done.
这是解决方案
直线和圆的设置可以动态设置,下面仅是直线和圆的示例
The settings for line and circle can be dynamic set, below is just an example of a line and circle
CircleComponent和HTML模板
CircleComponent and HTML template
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模板
LineComponent and HTML template
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
The ShapeComponent and 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
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,为svg在CSS中设置宽度的高度
html, set height in width in css for the svg
<svg>
<ng-container *ngFor="let shape of shapes; let i = index">
<ng-container svg-dynamic [componentData]="shape">
</ng-container>
</ng-container>
</svg>
其中最重要的部分是指令
And the most import part of it, the directive
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
And the app.component html
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<app-shapeholder></app-shapeholder>
</div>
app.component
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
And the 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 { }
还有我的应用的最终屏幕截图
And a final screen shot of my app
我希望这个答案对您有用,并且可以在您自己的应用中使用它.这个想法是创建动态模板视图
I hope you find this answer usefull and can use it in your own app. The idea is to create dynamic templates views
这篇关于如何从列表显示ng-templates的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!