【问题标题】:Getting reference of ngComponentOutlet获取 ngComponentOutlet 的参考
【发布时间】:2017-11-18 23:01:58
【问题描述】:

我正在使用 ngComponentOutlet 动态创建一个组件。 听起来像:

import {Component, NgModule} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

@Component({
  selector: 'alert-success',
  template: `
    <p>Alert success</p>
  `,
})
export class AlertSuccessComponent {  }

@Component({
  selector: 'alert-danger',
  template: `
    <p>Alert danger</p>
  `,
})
export class AlertDangerComponent {
  test = 'danger...';
}

@Component({
  selector: 'my-app',
  template: `
    <h1>Angular version 4</h1>
    <ng-container *ngComponentOutlet="alert"></ng-container>
    <button (click)="changeComponent()">Change component</button>
  `,
})
export class App {
  alert = AlertSuccessComponent;

  changeComponent() {
    this.alert = AlertDangerComponent;
    alert(this.alert.test);       <-- ???????
  }
}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, AlertSuccessComponent, AlertDangerComponent ],
  entryComponents: [AlertDangerComponent, AlertSuccessComponent],
  bootstrap: [ App ]
})
export class AppModule {}

在 changeComponent() 中,我尝试(我天真地猜测)获取当前组件的引用以向其提供数据,但它失败了 :(

我应该使用 ViewContainerRef,如何?

【问题讨论】:

  • 我认为没有办法获取组件。我看到了一个拉取请求来添加它,但它看起来不像被接受。您可以自己创建和添加组件,然后获得对创建的组件实例的引用,并且可以更新其属性。另见github.com/angular/angular/blob/…stackoverflow.com/questions/36325212/…
  • @GünterZöchbauer 我误解了 OP,以为他只需要渲染一个组件,但没有意识到必须动态进行。我改变了方法,检查一下,如果你愿意/可以的话,让我知道你的想法! :D
  • 我简要查看了您回答中的示例,但这并不是我理解他所要求的。我认为他应该使用我上面评论中第二个链接中演示的内容。
  • @GünterZöchbauer 也许我错过了一些东西,但在第二个链接中你建议ngComponentOutlet,他已经在使用它了。而且,我相信我们不能使用ngComponentOutlet 按需更改渲染的组件。这就是为什么在理解了 OP 之后我选择了 directive like 方法。如果我们找到ngComponentOutlet 的解决方案,我将在我自己的项目中实现它! :P
  • ngComponentOutlet 有这个限制,它不提供对创建的组件的引用。请参阅链接答案中的 RC.7 示例。

标签: angular components


【解决方案1】:

你必须把组件名称直接放在那里:

<ng-container *ngComponentOutlet="AlertDangerComponent;
            ngModuleFactory: alertDangerModule;"></ng-container>

我冒昧添加了Module,用于当您从与当前Module不同的Module中渲染组件时。

此外,为了使用 Module 选项,您需要在当前组件中使用它:

private alertDangerModule: NgModuleFactory<any>;

constructor(private compiler: Compiler) {
      this.alertDangerModule = compiler.compileModuleSync(AlertDangerModule);
}

如果您只想从当前模块加载 1 个组件,这就是您需要做的:

<ng-container *ngComponentOutlet="AlertDangerComponent"></ng-container>

NgComponentOutlet

用于导入模块:NgModuleFactory

更新(动态):

创建向量,如:

import AlertDangerComponent from './path';
import AlertSuccessComponent from './path';

export const MY_ALERTS = {
    'alertDanger': AlertDangerComponent,
    'alertSuccess': AlertSuccessComponent,
};

在您的组件中,您导入MY_ALERTS,您可以渲染与MY_ALERTS 一样多的组件。

或者你可以尝试动态渲染它,通过创建一个新的ng-container (还没有测试)

我正在使用它从一个巨大的向量中渲染组件,该向量包含具有其他值(例如布尔值)的组件类,因此我知道每次要加载哪个组件。

要渲染此向量内的组件,您可以:

<div *ngFor="let alert of MY_ALERTS | keys">
        <ng-container *ngComponentOutlet="MY_ALERTS[alert];
                 ngModuleFactory: commonAlertsModule;"></ng-container>
</div>

keys 只是一个 @Pipe,它返回对象的键(而不是值)

更新(替代方法):

我在想也许您可能会对这种其他方法感兴趣:使用@Component 作为'指令'。我自己解释一下:

使用 类似 选择器的指令声明您的组件:

@Component({
  selector: '[alert-success]',
  template: `
    <p>Alert success</p>
  `,
})
export class AlertSuccessComponent {  }

@Component({
  selector: '[alert-danger]',
  template: `
    <p>Alert danger</p>
  `,
})
export class AlertDangerComponent {
  test = 'danger...';
}

然后,根据场合,您只需调用其中一个即可:

@Component({
  selector: 'my-app',
  template: `
    <h1>Angular version 4</h1>
    <div *ngIf="alertDanger" alert-danger></div>
    <div *ngIf="alertSuccess" alert-success></div>
    <button (click)="changeComponent()">Change component</button>
  `,
})
export class App {
  alertSuccess = true;
  alertDanger = false;

  changeComponent() {
    this.alertSuccess = !this.alertSuccess;
    this.alertDanger = !this.alertDanger;
  }
}

在我的示例中(虽然没有测试)我初始化了成功警报。单击时,应将alertSuccess 设置为false,并将alertDanger 设置为true

【讨论】:

  • 好吧,如果我理解的话,所有组件都已加载,我只显示我想要的那些...
  • @Stef 好吧,在我的第二种方法中,您循环遍历向量并从那里选择要加载的组件。但我相信不会允许您在点击时更改组件。我的第三种方法,然后是 directive like 选择器,我认为会为您解决问题。
  • 第三种方法非常聪明,@SrAxi...我认为它会适合!
  • 顺便说一句,我很惊讶,像动态组件这样重要的东西在 Angular 中仍然如此棘手!
  • @Stef 是的,Angular 确实做出了巨大的改变,并且仍在做这些改变。这个功能可能会出现,但同时我们需要做一些变通方法。从第 2 版到第 4 版已经发生了巨大的变化。我们走在正确的道路上! ;)
【解决方案2】:

我也遇到了同样的问题,并做了一些阅读。 Angular 世界变化很快。在撰写本文时,这似乎是 Angular 指南中最官方的方法。请参阅此食谱食谱:

Angular Dynamic Component Loader

它使用“anchor”指令告诉 Angular 动态组件在模板中的位置。然后它继续使用组件工厂和视图容器 ref 来创建和插入动态组件,同时保存新添加的组件的实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-09
    • 1970-01-01
    • 2019-01-24
    • 2010-09-26
    • 1970-01-01
    • 2022-07-01
    相关资源
    最近更新 更多