【问题标题】:How do I dynamically create components with third party library in Angular?如何在 Angular 中使用第三方库动态创建组件?
【发布时间】:2022-01-20 03:14:31
【问题描述】:

使用 Angular 10

关于 SO 有很多与此类似的问题,但我还没有找到一个可以回答我的情况的问题。

我希望有人可以指导我。

我正在使用第三方库来显示 360° 照片。这个第三方库有一个内置的 API 来显示场景中的热点。只需为库提供您想成为热点的元素,其余的事情就交给它了。

我的大部分工作都按预期工作,但有几部分没有。

到目前为止,我正在像这样动态生成我的组件:

this._hotspotFactory = this.resolver.resolveComponentFactory(HotspotComponent);
const component = this._hotspotFactory.create(this.injector);

//Hydrate component with  bunch of data
component.instance.id = data.id;
...

// Create the Hotspot with Third Party
// Calling this third party method injects the native element into the DOM. 
// Passing the nativeElement in. Looks great at first glance. 
const hotspot = this._scene.createHotspot(data, component.location.nativeElement);

this.appRef.attachView(component.hostView);
component.hostView.detectChanges();

if(component.instance.over.observers.length) {
  hotspot.on('over', (evt) => {
    this.zone.run(() => {
      component.instance.over.emit(evt);
    });
  });
}

if(component.instance.out.observers.length) {
  hotspot.on('out', (evt) => {
    this.zone.run(() => {
      component.instance.out.emit(evt);
    });
  });
}

if(component.instance.navigate.observers.length) {
  hotspot.on('click', (evt) => {
    this.zone.run(() => {
      component.instance.navigate.emit(evt);
    })
  });
}

没有抛出错误,我成功地看到了热点应该在场景中的位置。甚至HotspotComponent 模板中的数据插值也会按预期发生。

但是,[ngStyle] 绑定永远不会导致 HotspotComponent 中的动态样式。

我 99% 确定这是因为组件中没有进行更改检测。

我使用this.appRef.attachView(component.hostView) 手动附加视图,因为第三方负责将元素注入 DOM,而不是 Angular。因此 Angular 需要了解它,以便执行更改检测。

即使手动调用attachView,我仍然认为 Angular 不知道视图中的这个组件,因为 Angular Chrome 扩展调试器没有在其开发工具中将其注册为视图中的已知组件... .尽管可以在屏幕和 DOM 中看到它。

我错过了什么?

【问题讨论】:

  • 问题是您的非角度库触发的事件不会链接到角度生命周期,反之亦然...您可能需要查看 ngZone,因为该服务提供了并且超出角度范围。
  • @TheFabio 我已经更新了我的答案。我正在收听来自第三方的事件,然后以角度触发这些事件。你是说我还需要监听组件生命周期事件然后对其采取行动?
  • 很难说没有深入了解您的源代码.. 但我的直觉是,当您调用 this._hotspotFactory.create 时,它会在与角度不同的范围内创建组件实例。你必须动态创建这个组件吗?
  • 你能在 Angular 组件中创建 hotspot 变量吗?
  • @TheFabio 您在上面看到的代码发生在服务中。在我的第一次尝试中,我在 Angular 组件中创建了 hotspot 变量。这导致视图中的 Angular 组件没有任何用途,并且第三方注入 DOM 的元素......因此存在重复。我是婴儿坐在两个......试图让他们保持同步。我希望通过动态创建组件来消除重复。我会继续挖掘。

标签: javascript angular angular-changedetection


【解决方案1】:

组件有什么变化检测策略? 当一个组件被添加到一个视图中时,它的生命周期钩子将被 angular(ngOninit, ngAfterContentInit 等) 触发。在其中记录一些内容,看看是否调用了主题生命周期钩子。无论采用何种变更检测策略,在组件添加到视图后,都应在组件上进行一个变更检测周期。

如果没有发生生命周期钩子调用,则意味着将元素添加到 DOM 中不涉及 Angular。

【讨论】:

    【解决方案2】:

    同样的问题,即使我也在几天前被卡住了。 这是我完整讨论的地方。你会得到你正在寻找的完整答案 StackOverflow Discussion

    Stackblitz Link Here

    【讨论】:

      【解决方案3】:

      似乎 Angular 有一个生命周期钩子正好适合您的用例 'ngDoBootstrap'

      由于我们无法调试您的完整源代码,根据您提到的信息,您尝试附加到视图的动态组件似乎不适用于 NgModule 中的 Angular。 角度引导的每个组件都必须在 NgModule 中

      您可以使用 'ngDoBootstrap' 动态引导它。

      它的使用方式如下:

      ngDoBootstrap(appRef: ApplicationRef) {
      
            this.fetchDataFromApi().then((componentName: string) => {
              if (componentName === 'ComponentOne') {
                appRef.bootstrap(ComponentOne);
              } else {
                appRef.bootstrap(ComponentTwo);
              }
            });
          }
      

      在您的情况下,您可以在将组件附加到视图之前执行此操作。

      ...
      appRef.bootstrap(component);
      this.appRef.attachView(component.hostView);
      component.hostView.detectChanges();
      ...
      

      请在此处查看文档:https://angular.io/api/core/ApplicationRef

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-13
        • 1970-01-01
        • 2019-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多