在非Angular应用程序中使用Angular 2组件

我有一个预先存在的,成熟的,非Angular Web应用程序的分支.我还有一些我希望重用的独立应用程序中现有的Angular 2组件.我想将现有的Angular组件分散到各个地方的非Angular应用程序中.我想知道这是否可行和可行.请注意,这与 Sprinkling Angular 2 components inside a non-angular page

相似但不完全相同.我有一个更具体的场景,我将在下面介绍.

目前,我已经想出如何通过引导包装我所需组件的模块来添加这些Angular组件的单个实例.例如.如果我想将AppComponent插入到我现有的非Angular应用程序中:

在app.module.ts中:

@NgModule({
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule { }

在app.component.ts中:

@Component({
  selector: 'my-app'
  template: '<span>{{value}}</span>'
  ...
})
export class AppComponent { 
   public value: string;
   ...
 }

每当我想要一个AppComponent时,我只需附加一个my-app元素并按如下方式引导模块:

platformBrowserDynamic().bootstrapModule(AppModule);

这完全正常,并为AppComponent的单个实例提供了我想要的精确结果.但是,我的用例要求我在DOM的不同位置同时有两个AppComponent实例.如果我第二次尝试引导AppModule,核心Angular代码会将第二个AppModule附加到DOM中首先出现的my-app元素,从而有效地删除我的第一个AppModule实例.有没有办法告诉Angular要追加哪个my-app元素?或者有什么方法可以解决这个问题?

HTML示例:

假设我追加一个< my-app>到< body>.然后我的HTML看起来像:

<body>
  <my-app>
  </my-app>
</body>

接下来,如果我调用platformBrowserDynamic().bootstrapModule(AppModule);并在AppComponent中的任何位置设置value =’111′,我的HTML看起来像:

<body>
  <my-app>
    <span>111</span>
  </my-app>
</body>

然后我将另一个my-app选择器添加到HTML中,所以它看起来像:

<body>
  <my-app>
    <span>111</span>
  </my-app>
  <my-app>
  </my-app>
</body>

然后,如果我调用platformBrowserDynamic().bootstrapModule(AppModule);并在AppComponent逻辑中的任何地方新设置的AppComponenet中设置value =’222′,我的HTML如下所示:

<body>
  <my-app>
    <span>222</span>
  </my-app>
  <my-app>
  </my-app>
</body>

当我想要的结果是:

<body>
  <my-app>
    <span>111</span>
  </my-app>
  <my-app>
    <span>222</span>
  </my-app>
</body>

总结:在非Angular应用程序中使用Angular组件是否可行且可取?是否可以同时拥有同一个角度模块的2个可见实例?

谢谢!

最佳答案 根据您的方案,我将编写以下代码:

let bootstrapComponentFn: (node: HTMLElement) => void;

platformBrowserDynamic().bootstrapModule(AppModule).then((moduleRef: 

  NgModuleRef<AppModule) => {
    const appRef = moduleRef.injector.get(ApplicationRef);
    const zone: NgZone = moduleRef.injector.get(NgZone);
    const rootComponentFactory = (moduleRef as any).bootstrapFactories[0];  

    bootstrapComponentFn = (node) => {
      zone.run(() => {
        const compRef = rootComponentFactory.create(Injector.NULL, [], node);
       appRef.attachView(compRef.hostView);
      })
    }; 
  });
}

一段时间以后

setTimeout(function() {
  let node = document.createElement('my-app');
  document.body.appendChild(node);

  bootstrapComponentFn(node);
}, 2000);

另见Plunker Example

点赞