I have a fork of a preexisting, mature, non-Angular web app. I also have some existing Angular 2 components from a separate app that I wish to reuse. I would like to sprinkle the existing Angular components into the non-Angular app in various places. I would like to know if this is possible and advisable. Note that this is similar but not identical to Sprinkling Angular 2 components inside a non-angular page . I have a more specific scenario that I describe below.
Currently, I have figured out how to add single instances of these Angular components by bootstrapping a module that wraps my desired component. E.g. if I want to insert AppComponent into my existing non-Angular app:
In app.module.ts:
@NgModule({
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
In app.component.ts:
@Component({
selector: 'my-app'
template: '<span>{{value}}</span>'
...
})
export class AppComponent {
public value: string;
...
}
Whenever I want an AppComponent, I simply append a my-app
element and bootstrap the module as follows:
platformBrowserDynamic().bootstrapModule(AppModule);
This works perfectly fine and gives the exact results I want for a single instance of AppComponent. However, my use cases require that I have two simultaneous instances of AppComponent in separate places of the DOM. If I attempt to bootstrap AppModule a second time, the core Angular code attaches the second AppModule to the my-app
element that appears first in the DOM, effectively erasing my first instance of AppModule. Is there a way to tell Angular which my-app
element to append to? Or is there any way around this?
HTML Example:
Let's say I append a <my-app>
to <body>
. Then my HTML looks like:
<body>
<my-app>
</my-app>
</body>
Next, if I call platformBrowserDynamic().bootstrapModule(AppModule);
and set value = '111'
anywhere in the AppComponent, my HTML looks like:
<body>
<my-app>
<span>111</span>
</my-app>
</body>
Then I add another my-app
selector to the HTML, so it looks like:
<body>
<my-app>
<span>111</span>
</my-app>
<my-app>
</my-app>
</body>
Then, if I call platformBrowserDynamic().bootstrapModule(AppModule);
and set value = '222'
in the newly created AppComponenet anywhere in the AppComponent logic my HTML looks like:
<body>
<my-app>
<span>222</span>
</my-app>
<my-app>
</my-app>
</body>
when I would like the desired result to be:
<body>
<my-app>
<span>111</span>
</my-app>
<my-app>
<span>222</span>
</my-app>
</body>
In summary: Is it possible and advisable to use Angular components throughout a non-Angular app? Is it possible to have 2 visible instances of the same Angular Module simultaneously?
Thanks!
Following your scenario i would write the following code:
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);
})
};
});
}
Some time later
setTimeout(function() {
let node = document.createElement('my-app');
document.body.appendChild(node);
bootstrapComponentFn(node);
}, 2000);
See also Plunker Example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With