为什么ng-content选择器在* ngFor内部不起作用

时间:2018-04-23 19:18:08

标签: angular

Here is the stackblitz code

如你所见

<div *ngFor="let number of numbers;let i = index">
        <div *ngIf="(number%2 !== 0);else even">
            <ul odd>{{number}}</ul>
        </div>
    <ng-template #even>
      <ul even>{{number}}</ul>
    </ng-template>    
</div>

我正在尝试使用ng-content选择器渲染值,但它在*ngFor循环内无效。为什么这样 ?如何使它工作?更像是img

我不想要两个ngFor循环,我希望它能与ng-content一起使用。

6 个答案:

答案 0 :(得分:6)

如果没有两个循环,你不能这样做。原因是ng-content是占位符,它接受内部的动态html。现在,当您在代码中循环时,您不会向evenodd选择器分配任何内容。但是,如果您将代码更改为

以下
<child>
    <div *ngFor="let number of numbers;let i = index" even>
        <div *ngIf="(number%2 !== 0);else even">
            <ul>{{number}}</ul>
        </div>
    <ng-template #even>
      <ul>{{number}}</ul>
    </ng-template>    
  <!-- <ul even>Why its rendering and not others??</ul> -->
    </div>
</child>

您将看到输出更改为

Change

这是因为没有ng-For的输出分配给even选择器。

如果您将模板更改为

<child>
    <div *ngFor="let number of numbers;let i = index" odd>
        <div *ngIf="(number%2 !== 0)">
            <ul>{{number}}</ul>
        </div>
    </div>
    <div *ngFor="let number of numbers;let i = index" even>
    <div *ngIf="(number%2 == 0)">
      <ul>{{number}}</ul>
    </div>    
    </div>
</child>

它会起作用

Working

另请注意,在ng-For内,您无法将内容附加到evenodd部分,即使该功能可用,也会覆盖最后一个值的部分。

ng-for离开它。以下代码

<child>
  <div>
    <div odd>
      This should be under odd
    </div>
  </div>
</child>

也不会工作

Not working

所以你想要实现的目标以及你试图实现它的方式并不受角度的支持。

答案 1 :(得分:3)

你可以用两个循环这样做:

<div>
    <ng-container *ngFor="let number of numbers; let isFirst=first">
        <h2 *ngIf="isFirst">Odd Numbers</h2>
      <p>{{(number%2>0? number : '')}}</p>
   </ng-container>

  <ng-container *ngFor="let number of numbers; let isFirst=first">
      <h2 *ngIf="isFirst">Even</h2>
      <p>{{(number%2==0? number : '')}}</p>
  </ng-container>
</div>

答案 2 :(得分:2)

其中一个解决方案是对数字数组进行排序。您可以使用自己的管道:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({name: 'oddFirst'})
export class OddFirstPipe implements PipeTransform {

  transform(numbers: number[], args: any[]): number[] {
    const odd = numbers.filter(num => num % 2 !== 0);
    const even = numbers.filter(num => num % 2 === 0);
    return [...odd, ...even];
  }

}

然后您可以在模板中使用它:

<div *ngFor="let number of numbers | oddFirst">
        <div *ngIf="(number%2 !== 0);else even">
            <ul odd>{{number}}</ul>
        </div>
    <ng-template #even>
      <ul even>{{number}}</ul>
    </ng-template>    
</div>

答案 3 :(得分:2)

你可以用纯CSS做到。

看一下修改过的StackBlitz。

https://stackblitz.com/edit/angular-zto8w1?file=app/app.component.html

CSS显示网格创造奇迹。请记住,IE上没有(完全)支持它。

答案 4 :(得分:2)

这是因为筑巢。

我运行了一些experiments on stackblitz,似乎内容根本无法嵌套,我们不能责怪*ngFor。即使在for循环中使用ng-container也无济于事。

答案 5 :(得分:0)

首先让我们看看投影/ ngContent是什么。
投影是Angular中非常重要的概念。它使开发人员能够构建可重用的组件,并使应用程序更具可扩展性和灵活性。

更简单地说,它有助于动态添加内容,这些内容可以来自服务器,作为组件内部的html或文本,而无需像document.createtextnode()那样创建DOM节点。

投射的参考:https://angular-2-training-book.rangle.io/handout/components/projection.html

投影类似于指令中的angularjs transclusion。 https://docs.angularjs.org/api/ng/directive/ngTransclude

让我们跳到你的问题。
这是正确的,我们需要两个循环来重复奇数和偶数的内容。根据您的要求。原因:ngFor在DOM中添加了相同模板的新实例。

工作代码
https://stackblitz.com/edit/angular-ymznfu?file=app%2Fapp.component.html

实施例

<强> App.component.html

<child>
    <ng-container odd>//this will work
     <ul>{{number[1]}}</ul>
    </ng-container>
 </child>

<强> child.component.html

<ng-content select="[odd]"></ng-content>

上面的示例将工作原因,我们正在ngContent中投射最外面的dom节点。

您可以尝试在代码下面进行投影

<强> app.component.html

 <child>
        <ng-container>
            <ng-content select="[odd]"></ng-content>
        </ng-container>
    </child>

上面的代码不会投影原因Angular只检查组件中可用的最外层节点,即代码中的原因

<ul odd>Something</ul>

正在投射而其他人没有。