"The selector app-root did not match any elements" when dynamically injecting Angular 5 app into iframe

Viewed 386

We have a unique situation where we manually inject an iframe into a page containing an Angular 5 app. The user can include this Javascript file onto any HTML page which in turn injects the iframe. If I hardcode I don't get the error. However, if I use the following code to inject the iframe, I get the following error. The Angular app seems to be looking for the app-root element before the iframe is even injected (if I put a breakpoint in the injectIframe() method, the error appears before the breakpoint is triggered).

VM4116 apm.min.js:16045 ERROR Error: The selector "app-root" did not match any elements
    at DefaultDomRenderer2.webpackJsonp.x35b.DefaultDomRenderer2.selectRootElement (VM4116 apm.min.js:43560)
    at BaseAnimationRenderer.webpackJsonp.x35b.BaseAnimationRenderer.selectRootElement (VM4116 apm.min.js:64508)
    at createElement (VM4116 apm.min.js:25018)
    at createViewNodes (VM4116 apm.min.js:28161)
    at createRootView (VM4116 apm.min.js:28089)
    at Object.createProdRootView [as createRootView] (VM4116 apm.min.js:28784)
    at ComponentFactory_.webpackJsonp.WT6e.ComponentFactory_.create (VM4116 apm.min.js:25702)
    at ComponentFactoryBoundToModule.webpackJsonp.WT6e.ComponentFactoryBoundToModule.create (VM4116 apm.min.js:18612)
    at ApplicationRef.webpackJsonp.WT6e.ApplicationRef.bootstrap (VM4116 apm.min.js:20418)
    at VM4116 apm.min.js:20154

Is there a way to manually bootstrap the application or something after the iframe has completed loading, so that it's not looking for before injectIframe has been called?

Here is the Javascript that injects the iframe (included in a script in the parent window):

  function injectIFrame(sessionId) {
    // Create the iframe
    var container;
    var containerStyle = '';

    if (typeof iframe === 'undefined') {
      container = document.createElement('iframe');
    }

    // Style the iframe
    containerStyle += 'width: 100%;';
    containerStyle += 'border: none;';
    container.style.cssText = containerStyle;

    container.title = "APM";
    container.src = 'https://localhost:4200/static/apm/' + VERSION + '/index.html';
    container.id = 'mc-apm-iframe';
    container.frameborder="1";
    container.style.zIndex = 9999;
    container.style.backgroundColor = "transparent";
    container.style.border = "1px";
    container.style.overflowX = "hidden";
    container.style.overflowY = "auto";
    container.style.left = "0px";
    container.style.top = "0px";
    container.style.width = "0px";
    container.style.height = "0px";

    document.body.appendChild(container);

    apmContainer = document.getElementById(container.id).contentWindow;
  }

app.module.ts:

const appRoutes: Routes = [
  {
    path: '',
    redirectTo: 'home-page',
    pathMatch: 'full'
  }
];

/*
 * Main module for the app that boostraps everything.
 */
@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule,
    FormsModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    RouterModule.forRoot(
      appRoutes
    )
  ],
  declarations: [
    RootComponent,
    AppComponent
  ],
  providers: [
    AppGuard,
    WindowRefService,
    EventsService,
    MessageService,
    ApmSharedService,
    {
        provide: HTTP_INTERCEPTORS,
        useClass: AppInterceptor,
        multi: true,
    },
    {provide: APP_BASE_HREF, useValue : '/' }
  ],
  bootstrap: [RootComponent]
})

export class AppModule { }

root.component.ts:

@Component({
    selector: 'app-root',
    template: '<router-outlet></router-outlet>'
})

export class RootComponent {}

app.component.ts:

@Component({
    selector: 'app-comp',
    templateUrl: './app.component.html'
})

export class AppComponent implements AfterViewInit {

  ...... [some stuff] .....

}
0 Answers
Related