2017-09-22 4 views
-1

Ich habe durch viele verschiedene Blog-Beiträge und Themen hier gelesen, um zu sehen, wie oder auch wenn, was ich mit Templates tun möchte getan, aber nichts gefunden haben, was funktioniert.Angular 4 und dynamische Vorlagen

Wir haben ein Symbol Komponente, die ganz einfach in der Struktur ist, die durch einfach unter Verwendung der Komponente und Spezifizierungs eingerichtet ist, das Symbol und Größe in der Vorlage benötigt wird, es zu benutzen:

import {Component, Input} from '@angular/core'; 

@Component({ 
    selector: 'comp-icon', 
    template: ` 
     <span class="{{ class }}" *ngIf="icon === 'error'" > 
      <svg [attr.height]="size" viewBox="0 0 48 48" [attr.width]="size" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg> 
     </span> 
     <span class="{{ class }}" *ngIf="icon === 'success'" > 
      <svg [attr.height]="size" viewBox="0 0 48 48" [attr.width]="size" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg> 
     </span> 
    ` 
}) 
export class IconComponent { 
    @Input() icon: string; 
    @Input() size: number; 
    @Input() class: string; 

    constructor() { 
    } 
} 

Das Problem ist, dass die oben wiederholt sich für viele weitere Zeilen und wir versuchen, die Fähigkeit hinzufügen, benutzerdefinierte SVG-Bilder aus den verschiedenen Anwendungen, die die Bibliothek, die diese Komponente implementiert ist, zu der Liste hinzufügen. Bisher ist dies, was ich habe es geschafft, das ist im Grunde zeigt, was wir erreichen wollen:

import {Component, Input, OnInit, ViewChild} from '@angular/core'; 
import {Icons} from './icons'; 

@Component({ 
    selector: 'comp-icon', 
    template: ` 
     <span class="{{ class }}"> 
      <ng-container [ngTemplateOutlet]="iconContent"></ng-container> 
     </span> 
    ` 
}) 
export class IconComponent implements OnInit { 
    @Input() icon: string; 
    @Input() size: number; 
    @Input() class: string; 

    @ViewChild('iconContent') iconContent: any; 

    constructor() { 
    } 

    ngOnInit() { 
     this.iconContent = (Icons.find(icon => icon.name === this.icon) || { name: '', content: '' }).content; 
    } 
} 

und die entsprechenden icons.ts sieht wie folgt aus:

export interface IIcon { 
    name: string; 
    content: string; 
} 

export const Icons: IIcon[] = [ 
    { 
     name: 'error', 
     content: `<svg [attr.height]="{SIZE}" [attr.width]="{SIZE}" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg"> 
     </svg>` 
    }, 
    { 
     name: 'success', 
     content: `<svg [attr.height]="{SIZE}" [attr.width]="{SIZE}" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg"> 
     </svg>` 
    }, 
]; 

Ist es überhaupt möglich, dynamisch den Inhalt eines Abschnitts einer Komponente auf diese Weise angeben, in diesem Fall die Svg? Ich habe einiges über Richtlinien gelesen, die in der Lage sind, dies zu erreichen, aber nichts steht wirklich heraus oder ich habe nicht wirklich herausgefunden, wie.

+0

Sie möchten Komponenten oder Winkelattribute und andere Bindungen verwenden, dann müssen Sie die Komponente zur Laufzeit kompilieren. Siehe zum Beispiel https://stackoverflow.com/questions/38888008/how-can-i-use-create-dynamic-template-to-compile-dynamic-component-with-angular –

+0

Nun, ich möchte nicht unbedingt _want_ tun das, aber es sieht nicht so aus, als hätte ich eine große Auswahl, da 'innerHTML' svgs nicht mag. Danke für den Link, ich werde es mir ansehen. P.S. Ich bin mir nicht sicher, wofür das Down-Vote bestimmt war, wer auch immer es getan hat. – DavidIQ

+0

Sie können Svg mit innerHTML, aber keine Bindungen verwenden. Sie müssen möglicherweise als sicher markieren https://stackoverflow.com/questions/31548311/angular-2-html-binding/41089093#41089093. Sie können die TypScript-String-Interpolation ** verwenden, bevor Sie sie an innerHTML anstelle von Bindungen übergeben. –

Antwort

0

Sie könnten innerHTML für die Eigenschaftenbindung verwenden. Wenn Sie eine Komponente erstellen möchten, sollten Sie die Vorschläge von Günter Zöchbauer überprüfen.

<div [innerHTML]="iconContent"> 
</div> 

könnte andere mögliche Lösung

export const Icons: IIcon[] = [ 
    { 
     name: 'error', 
     width: '50px', 
     heigth: '50px', 
     viewBox: '0 0 48 48', 
     xmlns: "http://www.w3.org/2000/svg" 
    } 
]; 

Und dann in der Komponente html seine

<svg [attr.width]="iconContent.width" [attr.heigth]="iconContent.height" [attr.viewBox]="iconContent.viewBox" [attr.xmlns]="xmlns"></svg> 
+0

Ja, ich habe das schon ausprobiert, aber Angular gibt mir eine nette 'WARNUNG: Desinfizierung von HTML, die einige Inhalte entfernt ', was offensichtlich bedeutet, dass die gesamte svg entfernt wird. – DavidIQ

+0

@DavidlQ Sie müssten eckig Sie wissen, was Sie tun, deaktivieren Sie die Ausgabebereinigung für die Svg-Inhalt überprüfen https://angular.io/guide/security –

0

Der richtige Weg, dies in der Tat zu tun war ngComponentOutlet zu verwenden, wie ich versuche, ursprünglich wurde. Basierend auf this post habe ich es realisiert, so ziemlich wörtlich, auf folgende Weise:

import { Compiler, Component, ElementRef, Input, NgModule, NgModuleFactory, OnInit, ViewChild } from '@angular/core'; 
import { IconsProvider } from './icons.provider'; 

@Component({ 
    selector: 'comp-icon', 
    template: ` 
     <ng-container *ngComponentOutlet="dynamicIconComponent; 
         ngModuleFactory: dynamicIconModule;"></ng-container> 
    ` 
}) 
export class IconComponent implements OnInit { 
    @Input() icon: string; 
    @Input() size: number; 
    @Input() class: string; 

    public dynamicIconComponent: any; 
    public dynamicIconModule: NgModuleFactory<any>; 

    constructor (private _iconsProvider: IconsProvider, private _compiler: Compiler) { 
    } 

    ngOnInit() { 
     const selectedIcon: string = this._iconsProvider.getIcon(this.icon); 

     if (selectedIcon != null) { 
      this.dynamicIconComponent = this.createNewIconComponent(selectedIcon, this.class, this.size); 
      this.dynamicIconModule = this._compiler.compileModuleSync(this.createIconComponentModule(this.dynamicIconComponent)); 
     } 
    } 

    private createIconComponentModule(iconComponentType: any) { 
     @NgModule({ 
      imports: [], 
      declarations: [ 
       iconComponentType 
      ], 
      entryComponents: [iconComponentType] 
     }) 
     class RuntimeIconComponentModule {} 

     return RuntimeIconComponentModule; 
    } 

    private createNewIconComponent(iconContents: string, iconClass: string, iconSize: number) { 
     @Component({ 
      selector: 'dynamic-icon-component', 
      template: `<span class="{{ iconClass }}">${iconContents}</span>` 
     }) 
     class DynamicIconComponent implements OnInit { 
      private iconContents: string; 
      private iconClass: string; 
      private size: number; 

      ngOnInit() { 
       this.iconContents = iconContents; 
       this.iconClass = iconClass; 
       this.size = iconSize; 
      } 
     } 

     return DynamicIconComponent; 
    } 
} 

Die Kommentare und Anregungen schließlich die Suche nach dem Weg zur Antwort sehr nützlich waren. Vielen Dank.