InterviewHubPRO
Section Overview
Q269

Question 269 of 283

Part 10: Reactive Forms, Standalone Components, Signals & NgRx (256 - 283)

95%
Angular & Signals (283 Qs)•Part 10: Reactive Forms, Standalone Components, Signals & NgRx (256 - 283)

How to set ngFor and ngIf on the same element?

In Angular, placing both *ngFor and *ngIf on the same HTML element is invalid and throws a compile-time template error:

cmd
Template parse errors: Can't have multiple template bindings on one element. Use only one attribute prefixed with *

This error occurs because Angular expands asterisk (*) syntax into an <ng-template> wrapper. Having two asterisks on a single tag creates an ambiguous nesting hierarchy for the template compiler.

1. Classic Solution: Using <ng-container>

In classic Angular, you resolve this by placing one of the structural directives on an <ng-container> wrapper. The <ng-container> is a logical grouping element that Angular does not render into the final DOM:

html
<!-- Scenario A: Render the list only if items array exists -->
<ng-container *ngIf="users && users.length > 0; else noUsersTemplate">
  <ul>
    <li *ngFor="let user of users; trackBy: trackById">
      {{ user.name }}
    </li>
  </ul>
</ng-container>

<ng-template #noUsersTemplate>
  <p>No users registered.</p>
</ng-template>

<!-- Scenario B: Filter items inside the loop (only render active users) -->
<ul>
  <ng-container *ngFor="let user of users; trackBy: trackById">
    <li *ngIf="user.isActive">
      {{ user.name }}
    </li>
  </ng-container>
</ul>

2. Modern Solution: Built-in Control Flow (@if and @for) (Angular 17+)

In modern Angular (v17+), built-in control flow completely eliminates the multiple-structural-directive conflict because @if and @for are native template blocks rather than directive attributes:

html
<!-- Clean, natural nesting with zero dummy containers -->
@if (users && users.length > 0) {
  <ul>
    @for (user of users; track user.id) {
      @if (user.isActive) {
        <li>{{ user.name }}</li>
      }
    }
  </ul>
} @else {
  <p>No users registered.</p>
}

3. Best Practice Architectural Recommendation

[!TIP] Filtering in Templates vs. Component Signals: While nesting @if inside @for works, filtering large collections directly in the template can hurt performance. Instead, use a computed Signal in your component to pre-filter items:

typescript
activeUsers = computed(() => this.users().filter(u => u.isActive));

In template:

html
@for (user of activeUsers(); track user.id) {
  <li>{{ user.name }}</li>
}