当前位置: 首页 > 面试题库 >

Angular 2.1.0动态动态创建子组件

子车轶
2023-03-14
问题内容

我正在尝试做的angular2.1.0是动态创建子组件,这些子组件应该注入到父组件中。例如父组件是lessonDetails包含共享的内容为所有课程如如按钮Go toprevious lessonGo to next lesson和其他东西。根据路线参数,应将作为 子组件的 课程内容动态注入到父组件中。子组件(课程内容)的HTML定义为外部某处的纯字符串,它可以是类似以下内容的对象:

export const LESSONS = {
  "lesson-1": `<p> lesson 1 </p>`,
  "lesson-2": `<p> lesson 2 </p>`
}

通过innerHtml父组件 模板中进行以下操作可以轻松解决问题。

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

在每次更改路线参数时,lessonContent父组件的属性都会更改(内容(新模板)将从LESSON对象中获取),从而导致父组件模板被更新。这可以工作,但是角度不会处理注入的内容,innerHtml因此无法使用routerLink和其他东西。

const metadata = new ComponentMetadata({
  template: this.templateString,
});

在哪里templateString传递给子组件作为子组件的Input属性。双方MetaDataComponentResolver已被弃用/去掉angular2.1.0

因此,问题不仅仅涉及动态组件的创建(如在几个相关的SO问题中所述),如果我为每个课程内容都定义了组件,问题将更容易解决。这意味着我需要为100个不同的课程预先声明100个不同的组件。不推荐使用的元数据提供的行为类似于在单个组件运行时更新模板(在路由参数更改时创建和销毁单个组件)。

更新1:
因为它似乎在近角的释放,即要创建需要的所有组件/注入动态需要被预先定义entryComponents之内@NgModule。在我看来,与上述问题相关,如果我需要上100堂课(需要动态动态创建的组件),则意味着我需要预定义100个组件

更新2: 基于更新1,可以通过ViewContainerRef.createComponent()以下方式完成:

// lessons.ts
@Component({ template: html string loaded from somewhere })
class LESSON_1 {}

@Component({ template: html string loaded from somewhere })
class LESSON_2 {}

// exported value to be used in entryComponents in @NgModule
export const LESSON_CONTENT_COMPONENTS = [ LESSON_1, LESSON_2 ]

现在在路由参数的父组件中更改

const key = // determine lesson name from route params

/**
 * class is just buzzword for function
 * find Component by name (LESSON_1 for example)
 * here name is property of function (class)
 */

const dynamicComponent = _.find(LESSON_CONTENT_COMPONENTS, { name: key });
const lessonContentFactory = this.resolver.resolveComponentFactory(dynamicComponent);
this.componentRef = this.lessonContent.createComponent(lessonContentFactory);

父模板如下所示:

<div *ngIf="something" #lessonContentContainer></div>

where
lessonContentContainer装饰@ViewChildren属性,lessonContent装饰为@ViewChild,并初始化ngAfterViewInit ()为:

ngAfterViewInit () {
  this.lessonContentContainer.changes.subscribe((items) => {
    this.lessonContent = items.first;
    this.subscription = this.activatedRoute.params.subscribe((params) => {
      // logic that needs to show lessons
    })
  })
}

解决方案有一个缺点 ,那就是所有组件(LESSON_CONTENT_COMPONENTS)都需要预定义。有没有一种方法可以使用单个组件并在运行时更改该组件的模板(更改路由参数)?


问题答案:

您可以使用以下HtmlOutlet指令:

import {
  Component,
  Directive,
  NgModule,
  Input,
  ViewContainerRef,
  Compiler,
  ComponentFactory,
  ModuleWithComponentFactories,
  ComponentRef,
  ReflectiveInjector
} from '@angular/core';

import { RouterModule }  from '@angular/router';
import { CommonModule } from '@angular/common';

export function createComponentFactory(compiler: Compiler, metadata: Component): Promise<ComponentFactory<any>> {
    const cmpClass = class DynamicComponent {};
    const decoratedCmp = Component(metadata)(cmpClass);

    @NgModule({ imports: [CommonModule, RouterModule], declarations: [decoratedCmp] })
    class DynamicHtmlModule { }

    return compiler.compileModuleAndAllComponentsAsync(DynamicHtmlModule)
       .then((moduleWithComponentFactory: ModuleWithComponentFactories<any>) => {
        return moduleWithComponentFactory.componentFactories.find(x => x.componentType === decoratedCmp);
      });
}

@Directive({ selector: 'html-outlet' })
export class HtmlOutlet {
  @Input() html: string;
  cmpRef: ComponentRef<any>;

  constructor(private vcRef: ViewContainerRef, private compiler: Compiler) { }

  ngOnChanges() {
    const html = this.html;
    if (!html) return;

    if(this.cmpRef) {
      this.cmpRef.destroy();
    }

    const compMetadata = new Component({
        selector: 'dynamic-html',
        template: this.html,
    });

    createComponentFactory(this.compiler, compMetadata)
      .then(factory => {
        const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);   
        this.cmpRef = this.vcRef.createComponent(factory, 0, injector, []);
      });
  }

  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }    
  }
}


 类似资料:
  • 问题内容: 你好,我有这个设置 我需要为每个按钮获取以下内容 在Java中是否可以为我声明的每个按钮动态创建此按钮?因为当我有5个按钮时,我不需要3x5 = 15行代码,而是只有几行具有动态创建的按钮。 问题答案: 编写一个小循环并将您的按钮存储在数组中:

  • 你好,我已经准备好了 我需要为每个按钮获得以下内容 在Java中,是否可以为我声明的每个按钮动态创建它?因为当我有5个按钮时,我不希望3x5=15行代码,而只希望有几行动态创建的按钮。

  • 问题内容: 给定一个类名,我想动态创建一个Groovy类,向其添加属性和方法。我使用创建新类 对于我使用的方法 其中it.key是字符串(方法名),it.value是闭包。这很方便,因为我可以指定方法参数类型并进行类型检查。但是,如果不给它赋值,就无法指定动态创建的属性类型。我可以通过显式定义属性的getter和setter来解决此问题。这可行,但是metaClass.name = value或m

  • 问题内容: 我在mysql上创建数据库。首先创建主体表,每个表平均有30列。日志表的标准是引用表的pk加上每列*2。像这样: 参考表: 日志表: 现在,我想要创建一个过程,在该过程中,我将表名作为参数传递,并生成表日志查询并执行它。 做这个的最好方式是什么? 问题答案: 为了使一个字符串代表一个表(或数据库)名称,您将需要用变量连接查询字符串,并在存储过程中准备/执行一条语句。这是一个基本示例。

  • 问题内容: 我陷入GWT CellTable的问题。我需要动态创建单元表,而我没有实体(Bean)类。我已经看到了所有celltable的示例,并且在没有实体类的情况下进行了大量搜索。 我需要根据数据库中存储的一些元数据动态填充表。我可以创建表结构 考虑有两个类,一个是GRID,另一个是COLUMN,用于元数据和列定义。GRID将具有COLUMNS的列表作为列定义 现在,我需要从数据库中获取网格并

  • 问题内容: 我需要动态创建一个类。为了更详细,我需要动态创建Django类的子类。 通过“动态”,我打算基于用户提供的配置创建一个类。 例如 我想要一个命名为该类的子类的类。 该类应具有所选属性的列表。 ....在这种情况下 有什么有用的提示吗?:) 问题答案: 您可以通过调用内置函数并传递适当的参数来动态创建类,例如: 它适用于新型类。我不确定这是否也适用于老式类。