3

I've got a working angular application. I want to integrate it with a content management system that produces static pages, but for this I need to use content projection from the index.html page.

Something like this:

    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>AngularBacktest</title>
        <base href="/">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="icon" type="image/x-icon" href="favicon.ico">
      </head>
      <body>
        <app-root>Text injected from index.html</app-root>
      </body>
    </html>

Then, the app-root component implements content projection by including <ng-content></ng-content> in its template:

  @Component({
    selector: 'app-root',
    template: '<p>Content projection from outside:11<ng-content></ng-content>11</p>',
    styleUrls: ['./app.component.css']
  })
  export class AppComponent { }

Alas, things don't seem to work like I would like. After compiling and launching the application, the rendered result is the following:

  • Content projection from outside:1111

This is my question:

  • Is it possible to use content projection from outside the angular application, like in the example above?
  • If yes, how? If not, why?

Edit: In some comments I get questioned as of why should I want something like this. So here is why: my Angular application provides configurable components implementing financial back-testing simulations. This involves fetching historical quotes, running a simulation and showing the results in a graph. I would like to display the simulations running in an environment like WordPress, a Dokuwiki, or even static pages served by some Apache instance. This is could be an example:

    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>Pure Buy &amp; Hold example</title>
        <base href="./">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="icon" type="image/x-icon" href="favicon.ico">
      </head>
      <body>
        <p>This simulation shows a pure <em>Buy &amp; Hold</em>, investing
        100'001USD in the S&amp;P500, between 2000, January the 1st, and    
        2020 January the 1st:</p>
        <app-root>
          <simulation start="2000-01-01" end="2020-4-9" quotes="SPY">
              <chart-report>
                  <chart-report-configuration show="SPY.CLOSE" showDataAs="LINE" showDataOn="LEFT"    normalize="true"    ></chart-report-configuration>
                  <chart-report-configuration show="BAH.NAV"     showDataAs="LINE" showDataOn="LEFT"    normalize="true"    ></chart-report-configuration>
              </chart-report>
              <accounts>
                  <swiss-quote id="BAH" cash="100000">
                      <strategy>
                          <buy-and-hold assetName="SPY"></buy-and-hold>
                      </strategy>
                  </swiss-quote>
              </accounts>
          </simulation>
        </app-root>
        <p/>Blah blah blah blah</p>
      </body>
    </html>
jmgonet
  • 1,134
  • 18
  • 18

1 Answers1

1

Currently, with Angular up to v15, this is not possible to inject app-root content with ng-content, but it is a feature under consideration. There is an open issue for that with more details: https://github.com/angular/angular/issues/4946


My solution to show the Initial Loading Indicator is to have the default app-root content initially outside the app-root and then project it into the app-component.

index.html

...
<body>
  <div id="initialization-container">
    Initializing...
  </div>
  <app-root></app-root>
</body>
...

app.component.html

<ng-container *ngIf="isInitializing$ | async; else appInitialized">
  <app-initialization-container/>
</ng-container>

<ng-template #appInitialized>
  APPLICATION
</ng-template>

initialization-container.ts

import {AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Renderer2} from '@angular/core';

@Component({
  selector: 'app-initialization-container',
  template: '',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class InitializationContainerComponent implements AfterViewInit {
  constructor(
    private render: Renderer2,
    private hostRef: ElementRef
  ) {
  }

  ngAfterViewInit() {
    const el = document.getElementById('initialization-container');
    if (el != null) {
      this.render.appendChild(this.hostRef.nativeElement, el);
    }
  }
}

Another possibility for the loading indicator use-case would be just to remove it from the DOM, when loading is completed, but this example should also demonstrate, how to project content into the application to fit your use-case.

mangei
  • 747
  • 7
  • 16