【问题标题】:Dynamic Template in Component Angular 6组件 Angular 6 中的动态模板
【发布时间】:2019-03-10 20:56:14
【问题描述】:

我是 Angular 的新手,所以如果我搞砸了行话,我很抱歉。 我正在尝试在我的组件中动态使用 templateURL (html),Class 函数将保持不变,但 html 会根据 binType

而改变

这是我的组件类源码

import { Component, OnInit, Input, Output, EventEmitter, AfterViewInit, ViewContainerRef, ViewChild, Compiler, Injector, NgModule, NgModuleRef } from '@angular/core';

declare var module: {
  id: string;
}

@Component({
  selector: 'app-cart-bin',
  styleUrls: ['./cart-bin.component.css'],  
  template: ` 
      <ng-template #dynamicTemplate></ng-template>
    `

})

export class CartBinComponent implements AfterViewInit, OnInit {

  @ViewChild('dynamicTemplate', {read: ViewContainerRef}) dynamicTemplate;


  public cols = 3;
  public rows = 3;

  @Input() binType = "";

  @Input() toteList = [];

  @Output() callbackMethod = new EventEmitter<string>();

  constructor(private _compiler: Compiler, private _injector: Injector, private _m: NgModuleRef<any>) { }

  ngOnInit() {
    console.log(this.binType);
  }

  ngAfterViewInit() {

    let tmpObj;

    console.log(tmpObj);

    if ((this.binType) == "2") {
      tmpObj = {
        moduleId: module.id,
        templateUrl : './cart-bin.component_02.html'
      };
    } else {
      tmpObj = {
        moduleId: module.id,
        templateUrl : './cart-bin.component_01.html'
      };
    }

    console.log(tmpObj);

    const tmpCmp = Component(tmpObj)(class {});

    const tmpModule = NgModule({declarations: [tmpCmp]})(class {});

    this._compiler.compileModuleAndAllComponentsAsync(tmpModule).then((factories) => {
      const f = factories.componentFactories[0];
      const cmpRef = f.create(this._injector, [], null, this._m);
      cmpRef.instance.name = 'dynamic';
      this.dynamicTemplate.insert(cmpRef.hostView);
    });
}

  getToteBoxClass(toteData){
    ...
  } 

  getToteIcon(toteData){
    ...
  }

  toteSaveClick(toteData){
    ...
  }
}

正在编译,但模板未解析并出现以下错误

ERROR Error: Template parse errors:
Can't bind to 'ngStyle' since it isn't a known property of 'div'.

Html 是正确的,我直接将它用作@Component TypeDecorator 的一部分

【问题讨论】:

    标签: angular ng-template


    【解决方案1】:

    除了使用编译器和创建动态组件在角度上是非常反模式的事实之外,我相信您可以通过将 CommonModule 添加到您的 NgModule 声明中来修复您的错误:

    NgModule({imports: [CommonModule], declarations: [tmpCmp]})
    

    最好在模板中使用ngSwitchCase,创建两个从基础组件继承但具有不同模板的组件,并根据binType 让它呈现一个或另一个组件:

    模板:

    <ng-container [ngSwitch]="binType">
      <cart-bin-1 *ngSwitchCase="1"></cart-bin-1>
      <cart-bin-2 *ngSwitchCase="2"></cart-bin-2>
    </ng-container>
    

    ts:

    export abstract class CartBin {
      // some common cart bin logic here:
    }
    
    
    @Component({
      selector: 'cart-bin-1',
      templateUrl: './cart-bin.component_01.html' 
    })
    export class CartBin1 extends CartBin {
    
    }
    
    @Component({
      selector: 'cart-bin-2',
      templateUrl: './cart-bin.component_02.html' 
    })
    export class CartBin2 extends CartBin  {
    
    }
    

    使用它的好处是,AOT 包将不再包含编译器,从而使您的应用程序更小更快。另外,这看起来好多了:)

    【讨论】:

    • 谢谢,我使用了 ngSwitchCase。它有效。对不起,你能解释一下吗Besides the fact that using the compiler and creating dynamic components is pretty anti pattern
    • @MediocreDev 99.99% 的时间在使用 Angular 时不需要使用 Compiler 类。尤其是当您对 Angular 不熟悉,并且发现自己认为应该使用它时,请纠正自己并告诉自己有更好的方法,但您还不知道 :) 例如现在使用 ngwitchCae
    • 在上面的代码 sn-p 中,html 存在于文件中。但是,如果该 html 来自某个服务器并且其中包含自定义指令怎么办?最好的方法是什么?
    • @PierreDuc 在这里使用 switch case 并不是真正的解决方案。请检查此讨论。 github.com/angular/angular/issues/15275 如果我有 100 个垃圾箱怎么办?我应该创建这个巨大的开关吗?如果我也有 1000 - 开关?显然不是。所以你说这里的最终答案是“这不是 Angular 的任务”?
    • @azrahel 这一切都取决于您当前的情况。这个问题是一个刚接触角度并且使用错误的东西来完成错误的任务的人。我相信每个特定的用例都有自己的角度解决方案。如果您有 1000 种不同的选项,您可以尝试使用包含您要使用的组件的 Map 对象,结合 ngComponentOutlet 您可以走很长的路
    猜你喜欢
    • 1970-01-01
    • 2019-07-22
    • 2017-10-18
    • 2019-02-20
    • 2022-08-12
    • 2018-11-19
    • 1970-01-01
    • 2019-10-30
    • 1970-01-01
    相关资源
    最近更新 更多