Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 4 ngComponentOutlet loads dynamic components, but route content is not being rendered

I'm trying to load different 'parent' components and inject route content into these different parent components by targeting ng-content in each parent component. Essentially, each parent component handles the navigation and other boilerplate stuff based on device widths (small/mobile, medium/tablet, and large/desktop).

The content generated for each route in my application needs to get transcluded (injected) into the parent components. The content for each route targets specific injection points using ng-content.

I'm able to swap out the parent components using <ng-container *ngComponentOutlet="ResponsiveComponent;"></ng-container>. The problem is my route-generated content is not getting injected into the targeted ng-content locations in each parent component.

Here's the code for swapping out parent components. AppPageComponent extends ResponsiveComponent which monitors device width based on media queries.

@Component({
    selector: 'app-page',
    template: `
        <ng-container *ngComponentOutlet="ResponsivePageComponent;"></ng-container>     
    `,  
    styleUrls: [ './page.component.scss'],
    providers: []
})
export class AppPageComponent extends ResponsiveComponent implements OnInit, OnDestroy
{
    ResponsivePageComponent;

    constructor(
        injector: Injector,
        zone: NgZone)
    {
        super(zone);    
    }

    ngOnInit()
    {       
        this.IsSmallEnvironmentStream
            .subscribe
            (
                (isSmall: boolean) =>
                { 
                    if (isSmall)
                    { 
                        this.ResponsivePageComponent= AppPageSmallComponent;
                    }                   
                },
                (err) => { },
                () => {}
            );

        this.IsMediumEnvironmentStream
            .subscribe
            (
                (isMedium: boolean) =>
                { 
                    if (isMedium)
                    { 
                        this.ResponsivePageComponent = AppPageMediumComponent;
                    }                   
                },
                (err) => { },
                () => {}
            );

        this.IsLargeEnvironmentStream
            .subscribe
            (
                (isLarge: boolean) =>
                { 
                    if (isLarge)
                    { 
                        this.ResponsivePageComponent = AppPageLargeComponent;
                    }                   
                },
                (err) => { },
                () => {}
            );      
    }
}

Angular's documentation for NgComponentOutlet shows you can target optional list of projectable nodes to insert into the content (ng-content) placeholders. I followed the examples from Angular's documentation and was able to inject text nodes into the different ng-content placeholders in my parent components and it works for my small/medium/large parent components.

How do I get the content from my routes to inject into these different placeholders? It seems like I'm really close to getting this to work. I can inject in essence static content into the palceholders, but I can not figure out how to inject the content generated by routes into the placeholders.

UPDATE - 07/25/2017

I created this plunker demonstrating this scenario (https://plnkr.co/edit/hOwRX1Ml6gX0S8em6nd5?p=preview).

In the plunker, page-wrapper component uses ngComponentOutlet to load small/medium/large component depending upon device width. page-wrapper component is injecting static content into the placeholders in each small/medium/large component instead of injecting route content from page 1.

My objective is to have a page wrapper component to handle responsive needs like different navigation elements for small/medium/large responsive designs.

So, how can 'static' content be injected into dynamically loaded component's ng-content placeholders yet route generated content is not being injected into ng-content placeholders?

Thanks for your help.

like image 306
Tom Schreck Avatar asked Jul 23 '17 05:07

Tom Schreck


1 Answers

1) You can define ng-content places in your PageWrapperComponent and transclude them to dynamic component

page-wrapper.component.html

<ng-container *ngComponentOutlet="ResponsiveComponent; 
                                content: [[el1],[el2]]"></ng-container>
<div #el1>
  <ng-content></ng-content>
</div>
<div #el2>
  <ng-content select="[named-injection-point]"></ng-content>
</div>

Plunker Example

2) You can also use template reference variables(or custom directive) in parent component and @ContentChild in PageWrapperComponent to get transcluding sections.

page-one.component.html

<page-wrapper>
    <section #mainPoint>
        <h2>Page One</h2>
    </section>
    <section #namedPoint>
        <h3>Page One Content:</h3>
        <p>Lorem ipsum dolor.</p>
    </section>
</page-wrapper>

page-wrapper.component.ts

@ContentChild('mainPoint') mainPoint;
@ContentChild('namedPoint') namedPoint;

page-wrapper.component.html

<ng-container *ngComponentOutlet="ResponsiveComponent; 
        content: [[mainPoint.nativeElement],[namedPoint.nativeElement]]"></ng-container>

Plunker Example

like image 196
yurzui Avatar answered Oct 26 '22 23:10

yurzui