【问题标题】:Angular 7 Reusable ng-templatesAngular 7 可重用的 ng 模板
【发布时间】:2020-03-11 14:05:56
【问题描述】:

我目前正在创建一个可重用的 ngx-datatable 包装器组件,它将在我的整个应用程序中使用,因为每个表都不同,我需要多个 ng-templates 来满足每个组件的需求。

我的想法是创建一个SharedTemplates 组件,该组件将包含许多 ng-templates,并通过简单地将它们作为公共属性来公开它们,例如:

@ViewChild("yesNoTemplate") public yesNoTemplate: TemplateRef<any>;

以便我以后可以将它们用作:

tableComponents: TableComponents = new TableComponents();

     `{
        name: 'Aprobado',
        prop: 'aprobado',
        cellTemplate: this.tableComponents.yesNoTemplate
      }`

但这似乎不起作用,tableComponents 没有任何属性,我认为是因为它没有被渲染(?)。

使用组件本身作为模板不起作用,因为我收到错误消息:

TypeError: templateRef.createEmbeddedView is not a function

如何存储这些模板以供多次重复使用?

【问题讨论】:

  • 您能否提供您目前拥有的相关代码 - 使用cellTemplate 的模板创建表格所需的最低限度@(显然不是通过您想要采用的最终方法)。跨度>

标签: angular angular2-template ngx-datatable ng-template


【解决方案1】:

该错误可能是由于使用了已弃用的template

所以你应该使用ng-template 而不是templatehttps://angular.io/guide/angular-compiler-options#enablelegacytemplate

StackBlitz example

【讨论】:

  • 我正在使用 ng-template,我面临的问题不是获取同一组件中的模板,而是从不同组件中获取模板。
  • 啊!我明白。您想动态插入组件。也许这有帮助:angular.io/guide/dynamic-component-loader
【解决方案2】:

您应该在根级别实例化 SharedTemplatescomponent,然后将所有 ng-template 实例存储到共享服务。

这是我在 StackBlitz 上的演示:https://stackblitz.com/edit/angular-s5ffjr

【讨论】:

    【解决方案3】:

    建议为所需的每个模板创建组件,然后使用“ComponentFactoryResolver”解析它们并附加到主机组件。

    提供更大的可扩展性。

    let type = YesNoComponent;
    let factory = cfr.resolveComponentFactory(type);
    let instance = host.viewContainerRef.createComponent(factory);

    ComponentFactoryResolver

    ViewContainerRef

    【讨论】:

      【解决方案4】:

      您正在尝试以编程方式创建组件,然后访问它们的方法和属性。

      Angular 创建组件实例的方式是使用Factory resolver 来创建新组件,并使用ViewContainerRef 来附加和渲染组件。

      首先创建一个指令,用作您的一个表的 ViewContainerRef,它将呈现组件(我相信您现在缺少的)并允许您访问它的方法和属性。

      import { Directive, ViewContainerRef } from '@angular/core';
      
      @Directive({
        selector: '[appTable]'
      })
      export class TableDirective {
      
        constructor(public viewContainerRef: ViewContainerRef) { }
      
      }
      

      现在您可以将其添加到 ng-template 标签并使用 FactoryResolver 在其中渲染组件:

      
      import { Component, ComponentFactoryResolver, ViewChild, OnInit, ComponentRef } from '@angular/core';
      import { TableComponent } from './table/table.component';
      import { TableDirective } from './table.directive';
      
      @Component({
        selector: 'app-root',
        template: `
        <ng-template appTable></ng-template>
        `,
      })
      export class AppComponent implements OnInit {
      
        @ViewChild(TableDirective) tableHost: TableDirective;
        tableComponent: ComponentRef<TableComponent>;
      
        constructor(private componentFactoryResolver: ComponentFactoryResolver) {
      
        }
      
          ngOnInit() {
      
          // TableComponents = new TableComponents();  wrong way!
      
          /**
          * creating the component factory resolver
          */
          const tableFactory = this.componentFactoryResolver.resolveComponentFactory(TableComponent);
          const viewContainerRef = this.tableHost.viewContainerRef;
      
          /**
           * clearing just in case something else was rendered before
           */
          viewContainerRef.clear();
      
          /**
           * now you will be able to access the methods and properties of your component after this
           */
          this.tableComponent = viewContainerRef.createComponent(tableFactory);
        }
      }
      

      最后,当组件以编程方式呈现时,您需要将其添加到模块的 entryComponents 数组中:

      @NgModule({
        declarations: [
          AppComponent,
          TableComponent,
          TableDirective
        ],
        imports: [
          BrowserModule
        ],
        entryComponents: [TableComponent],
        providers: [],
        bootstrap: [AppComponent]
      })
      

      我创建了一个demo,所以它更清楚,您可以在 Luka Onikadze 的article 中阅读有关动态创建组件的更多信息。

      【讨论】:

        【解决方案5】:

        我不知道您使用的是哪个 Angular 版本,但我遇到了类似的问题。

        在我的情况下,我使用的是 Angular 9,并且我试图创建一个组件,其中必须加载一个模板,其中包含 html,但也插值字符串“{{}}”和样式必须应用于它以及。所以模板和样式都来自服务器。

        在我的任务中,我还尝试在 stackoverflow 上提出这个问题: Dynamically inject HTML and CSS on request.

        在某个时候,我开始在 Discord 的编码社区中提问,有人给了我一个 github 链接。

        感谢我收到的链接,我能够实现我所需要的:

        “根据请求动态加载模板。”

        感谢alarm9k's post

        如果不是那个帖子,我现在可能和你一样。

        我希望这是你所需要的。

        哦,为了构建表格(排序、过滤、分页等),我使用了Clarity Design System's Datagrid,不知道你的情况是否有趣。

        警告:

        我不得不提一下,它有 1 个不好的效果。您不能在生产模式下构建项目,因为它不包含此解决方案所需的角度编译器。我正在尝试自己解决这个问题,主要是因为应用程序大小急剧增加(在我的情况下从 2mb 增加到大约 40-45mb)。

        Using both AOT and JIT in production within an Angular 9 app

        【讨论】:

          猜你喜欢
          • 2020-05-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-03
          • 1970-01-01
          • 2015-09-11
          • 2020-05-23
          • 2013-12-04
          相关资源
          最近更新 更多