【问题标题】:Angular 4 ngComponentOutlet loads dynamic components, but route content is not being renderedAngular 4 ngComponentOutlet 加载动态组件,但未呈现路由内容
【发布时间】:2017-12-28 22:14:47
【问题描述】:

我正在尝试通过在每个父组件中定位ng-content 来加载不同的“父”组件并将路由内容注入这些不同的父组件。本质上,每个父组件都根据设备宽度(小型/移动设备、中型/平板电脑和大型/桌面设备)处理导航和其他样板文件。

为我的应用程序中的每个路由生成的内容需要被嵌入(注入)到父组件中。每条路由的内容使用ng-content定位特定的注入点。

我可以使用<ng-container *ngComponentOutlet="ResponsiveComponent;"></ng-container> 替换父组件。问题是我的路由生成的内容没有被注入到每个父组件中的目标ng-content 位置。

这里是替换父组件的代码。 AppPageComponent 扩展了 ResponsiveComponent,后者根据媒体查询监控设备宽度。

@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 的 NgComponentOutlet 文档显示您可以将可选的可投影节点列表作为目标,以插入到内容 (ng-content) 占位符中。我遵循了 Angular 文档中的示例,并且能够将文本节点注入到我的父组件中的不同 ng-content 占位符中,它适用于我的小型/中型/大型父组件。

如何从路由中获取内容以注入这些不同的占位符?看来我真的很接近让它发挥作用。我可以将本质上的静态内容注入占位符,但我不知道如何将路由生成的内容注入占位符。

更新 - 2017 年 7 月 25 日

我创建了这个plunker demonstrating this scenario (https://plnkr.co/edit/hOwRX1Ml6gX0S8em6nd5?p=preview)。

在 plunker 中,page-wrapper 组件使用 ngComponentOutlet 根据设备宽度加载小型/中型/大型组件。 page-wrapper 组件将静态内容注入到每个小型/中型/大型组件的占位符中,而不是从第 1 页注入路由内容。

我的目标是拥有一个页面包装器组件来处理响应式需求,例如针对小型/中型/大型响应式设计的不同导航元素。

那么,如何将“静态”内容注入到动态加载组件的 ng-content 占位符中,而路由生成的内容却没有注入到 ng-content 占位符中?

感谢您的帮助。

【问题讨论】:

  • router-outlet 未在 HTML 中定义。
  • 您好!你能说到底什么是行不通的吗? Route 3 不会通过选择器包含 ng-content?如果您将 plunker 中的代码减少到最少的复制,那就太好了
  • @yurzui - 感谢您的反馈。我已经澄清了笨蛋。 plunker 现在只有 2 条路线。 Route 1 使用“响应式”父组件,其内容不会注入到父组件的 ng-content 占位符中。 Route 2 使用“非响应式”父组件,其内容确实被嵌入到其父组件的 ng-content 占位符中。
  • 感谢您的澄清。您想在动态组件中注入嵌入的内容,而不是 staticContent 它只有在 ng-content 位于直接子组件上时才有效。我们需要一些解决方法

标签: angular angular2-ngcontent router-outlet ng-component-outlet


【解决方案1】:

1) 您可以在 PageWrapperComponent 中定义 ng-content 位置并将它们转换为动态组件

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) 您还可以在父组件中使用模板引用变量(或自定义指令),在PageWrapperComponent 中使用@ContentChild 来获取包含部分。

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

【讨论】:

  • ngComponentOutlet 指令使用@ContentChild nativeElements 数组将内容传递给动态加载的组件。我必须按特定顺序放置数组才能将注入的内容放入正确的 ng-content。有没有办法保证数组中的哪些项目被注入到动态加载的组件中正确的 ng-content 中?
  • @Tom Schreck 你必须保持秩序。 stackoverflow.com/questions/44284026/… 你应该按照适当的顺序传递数组 ng-content 出现在模板中。在这种情况下,Angular 不使用select 属性,仅使用索引
  • 我尝试使用内容传递值,但我无法读取另一个组件中的内容值。我正在使用角度 5
  • @VenkateswaranR 你能设置一个小复制吗?
  • 我遵循了您的第二个 plunker 示例。但我没有得到内容价值
【解决方案2】:

这是您所期待的吗?顺便说一句,我只测试了中型组件...

https://plnkr.co/edit/JgCQb4JVSHnHCueamerV?p=preview

我认为这是因为您尝试在一个组件中使用 ng-content,而该组件不是从包含您要注入的内容的组件中直接调用的。我所做的只是在 PageWrapperComponent 上添加一个 ng-content,使用它自己的选择器,然后将它传递给下一个组件,使用期望的选择器。

PageWrapperComponent...

<ng-content select="[injected-content]" named-injection-point></ng-content>

然后在 PageOneComponent 中使用 Wrapper 所期望的新选择器

<section injected-content>
  <h3>Page One Content:</h3>
  <p>Lorem ipsum ...</p>
</section>       

现在,当我单击第 1 页链接时,我可以在 Jimmy 和 Fred 下方看到第 1 页内容。

【讨论】:

  • 感谢您的回复。我需要用路线中的内容替换 Jimmy 和 Fred,而不是将路线数据放在 Jimmy & Fred 下面。我只是使用 Jimmy 和 Fred 作为将内容放置在动态组件中的示例。我不知道如何加载路线数据。
猜你喜欢
  • 2018-04-14
  • 1970-01-01
  • 2019-01-14
  • 1970-01-01
  • 2017-10-20
  • 2018-02-08
  • 2017-11-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多