为何ng-content选择器在*ngFor循环内无法生效?
Great question! Let's break down why ng-content fails in your *ngFor loop, then walk through solutions that let you build your desired layout without using two separate loops.
Why ng-content Doesn't Work Inside *ngFor
ng-content is Angular's content projection tool—it's designed to take static content defined outside a component and slot it into specific spots inside the component. The problem here is that ng-content can't dynamically bind to the context variables from an *ngFor loop.
In your code, each iteration of *ngFor has a unique number value, but ng-content doesn't "see" this dynamic variable. It can't pass the current number to the projected content, so your values never render correctly.
Solutions (No Dual *ngFor Required)
You have two solid paths to fix this, depending on whether you need a reusable component or just want to implement the logic directly in your current template.
Option 1: Direct Conditional Rendering (Simplest Approach)
Skip ng-content entirely and use Angular's built-in conditional directives right in your *ngFor loop. This keeps everything in one place and avoids overcomplicating things:
<div *ngFor="let number of numbers; let i = index"> <!-- Render odd numbers with your desired styling --> <ul class="odd" *ngIf="number % 2 !== 0">{{ number }}</ul> <!-- Render even numbers --> <ul class="even" *ngIf="number % 2 === 0">{{ number }}</ul> </div>
Or use the else syntax to make it cleaner:
<div *ngFor="let number of numbers; let i = index"> <ng-container *ngIf="number % 2 !== 0; else evenItem"> <ul class="odd">{{ number }}</ul> </ng-container> <ng-template #evenItem> <ul class="even">{{ number }}</ul> </ng-template> </div>
Add some CSS to style the odd/even items to match your example:
ul.odd { color: #e74c3c; list-style-type: square; } ul.even { color: #3498db; list-style-type: circle; }
Option 2: Reusable Component with Template Projection
If you want to encapsulate this logic into a reusable component (so you can use it across your app), replace ng-content with ng-template and ngTemplateOutlet. This lets you dynamically pass the loop's context variables to your projected content:
Step 1: Parent Component Template
Define the templates for odd/even items in your parent component, and pass your numbers array to the reusable component:
<app-number-list [numbers]="numbers"> <!-- Template for odd numbers: let-number captures the value passed from the loop --> <ng-template #oddItem let-number> <ul class="odd">{{ number }}</ul> </ng-template> <!-- Template for even numbers --> <ng-template #evenItem let-number> <ul class="even">{{ number }}</ul> </ng-template> </app-number-list>
Step 2: Reusable Child Component (app-number-list)
In the child component, use ContentChild to grab the templates from the parent, then use ngTemplateOutlet to render them inside the single *ngFor loop:
import { Component, Input, ContentChild, TemplateRef } from '@angular/core'; @Component({ selector: 'app-number-list', template: ` <div *ngFor="let num of numbers"> <ng-container *ngIf="num % 2 !== 0; else evenTemplate"> <!-- Render the odd template, passing the current number as context --> <ng-container *ngTemplateOutlet="oddTemplate; context: { $implicit: num }"></ng-container> </ng-container> <ng-template #evenTemplate> <!-- Render the even template, passing the current number as context --> <ng-container *ngTemplateOutlet="evenTemplate; context: { $implicit: num }"></ng-container> </ng-template> </div> ` }) export class NumberListComponent { @Input() numbers: number[] = []; // Grab the odd item template from the parent @ContentChild('oddItem') oddTemplate!: TemplateRef<any>; // Grab the even item template from the parent @ContentChild('evenItem') evenTemplate!: TemplateRef<any>; }
This approach keeps your code DRY, lets you customize the odd/even layouts per use case, and still uses only one *ngFor loop.
内容的提问来源于stack exchange,提问作者Shashank Vivek

