如何将 AsyncPipe 与 ngComponentOutlet 结合使用

问题描述 投票:0回答:1

我想基于 JSON 配置动态构建 UI。尝试将

ngComponentOutlet
AsyncPipe
一起使用,这样我就可以懒惰地
import(...)
组件。我的实现不起作用(请参阅Stackblitz 上的示例)。没有错误,组件也不会初始化。

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [NgComponentOutlet, NgFor, AsyncPipe],
  template: `
    <ng-container *ngFor="let component of schema">
      <ng-content *ngComponentOutlet="load(component.name) | async; inputs: component.inputs"></ng-content>
    </ng-container>
  `,
})
export class App {
  // schema returned from API call
  schema = [
    {
      name: 'Lazy1',
      inputs: {
        title: 'Lazy 1 Component',
      },
    },
    {
      name: 'Lazy2',
      inputs: {
        title: 'Lazy 2 Component',
      },
    },
  ];

  componentManifest: Record<string, { load: () => Promise<unknown> }> = {
    Lazy1: {
      load: () => import('./app/lazy-components/lazy1.component'),
    },
    Lazy2: {
      load: () => import('./app/lazy-components/lazy2.component'),
    },
  };

  async load(component: string) {
    return await this.componentManifest[component]
      .load()
      .then((c) => (c as any)[component]);
  }
}

angular lazy-loading async-pipe ng-component-outlet dynamic-components
1个回答
0
投票

要进行的更改:

  1. ngComponentOutlet
    属于
    ng-container
    所以我们可以修改代码来使用它。

  2. componentManifest
    的键必须包含组件名称,因为导入具有相同的名称。同样适用于模式数组的
    name
    属性。

  3. 我们可以在构造函数中预处理导入并将其存储在属性

    component
    中以供异步管道处理。否则,在每次更改检测期间都会不断调用加载方法,这是一个瓶颈。

完整代码:

import {
  AsyncPipe,
  CommonModule,
  NgComponentOutlet,
  NgFor,
} from '@angular/common';
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { firstValueFrom, from } from 'rxjs';
import 'zone.js';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [NgComponentOutlet, NgFor, AsyncPipe, CommonModule],
  template: `
    <ng-container *ngFor="let component of schema">
      <ng-container *ngComponentOutlet="(component['component'] | async); inputs: component.inputs"></ng-container>
    </ng-container>
  `,
})
export class App {
  // schema returned from API call
  schema: any = [
    {
      name: 'Lazy1Component',
      inputs: {
        title: 'Lazy 1 Component',
      },
    },
    {
      name: 'Lazy2Component',
      inputs: {
        title: 'Lazy 2 Component',
      },
    },
  ];

  componentManifest: Record<string, { load: () => Promise<unknown> }> = {
    Lazy1Component: {
      load: () => import('./app/lazy-components/lazy1.component'),
    },
    Lazy2Component: {
      load: () => import('./app/lazy-components/lazy2.component'),
    },
  };

  constructor() {
    if (this.schema?.length) {
      this.schema.forEach((item: any) => {
        item['component'] = this.load(item.name);
      });
    }
  }

  load(component: string): any {
    return this.componentManifest[component].load().then((c: any) => {
      return (c as any)[component];
    });
  }
}

bootstrapApplication(App);

Stackblitz 演示

© www.soinside.com 2019 - 2024. All rights reserved.