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

时间:2017-04-11 20:42:21

标签: angular typescript

我有一个预先存在的,成熟的,非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>

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

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

然后我在HTML中添加了另一个my-app选择器,如下所示:

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

然后,如果我在AppComponent逻辑中的任何地方调用platformBrowserDynamic().bootstrapModule(AppModule);并在新创建的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个可见实例?

谢谢!

1 个答案:

答案 0 :(得分: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