2017-09-22 410 views
-1

我一直在閱讀很多不同的博客文章和主題,看看我是如何甚至是想用模板做什麼,但還沒有找到任何可行的方法。Angular 4和動態模板

我們使用它的圖標組件是相當簡單的,其中通過簡單地使用所需要的模板圖標和大小的組件並指定成立了結構:

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() { 
    } 
} 

的問題是,上面重複了更多的行,我們試圖包括從將使用實現此組件的庫的各種應用程序添加自定義svg圖像到列表的能力。到目前爲止,這是我所管理的這基本上說明了什麼,我們正在努力做到:

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; 
    } 
} 

以及相應的icons.ts看起來是這樣的:

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>` 
    }, 
]; 

它是在所有可能的以這種方式動態指定組件的一部分的內容,在這種情況下,svg?我讀過一些關於能夠實現這一目標的指令,但沒有任何內容真的突出,或者我沒有真正想到如何。

+0

你想要使用組件或角度屬性和其他綁定,那麼你需要在運行時編譯組件。見例如https://stackoverflow.com/questions/38888008/how-can-i-use-create-dynamic-template-to-compile-dynamic-component-with-angular –

+0

嗯,我不一定_want_做但是,由於'innerHTML'不喜歡svgs,所以看起來並不像我有太多的選擇。感謝您的鏈接,我會仔細查看。 P.S.不知道什麼是倒票,誰做的。 – DavidIQ

+0

你可以使用svg和innerHTML,但沒有綁定。您可能需要將其標記爲安全https://stackoverflow.com/questions/31548311/angular-2-html-binding/41089093#41089093。在將**傳遞給innerHTML而不是綁定之前,您可以使用TypeScript字符串插值**。 –

回答

0

你可以使用innerHTML來進行屬性綁定,如果你想創建一個組件,那麼你應該檢查GünterZöchbauer的suggetion。

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

另一種可能的解決方案可能是

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

,然後在組件的HTML

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

是的,我試過這個,但Angular給了我一個很好的警告:清理HTML剝離了一些內容消息,這顯然意味着剝離整個SVG。 – DavidIQ

+0

@DavidlQ你需要告訴角你知道你在做什麼禁用輸出清除svg內容檢查https://angular.io/guide/security –

0

要做到這一點是確實使用ngComponentOutlet我最初嘗試的正確方法。基於this post我實現它,幾乎一字不差,以下列方式:

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; 
    } 
} 

的意見和建議都在輾轉我的方式來回答非常有用的。謝謝。