Skip to content

Fallback for <ng-content> does not work if projected content is inside a @if #62046

@Abreuvoir

Description

@Abreuvoir

Which @angular/* package(s) are the source of the bug?

core

Is this a regression?

No

Description

When using fallback on content projection, if the projected content is inside a if and its condition is false, it is still considered present and nothing appears.

Repro:

@Component({
  selector: 'test-projection',
  standalone: true,
  template: `
    <ng-content>Fallback</ng-content>
  `,
})
export class ContentProjectComponent {}

@Component({
  selector: 'app-root',
  imports: [ContentProjectComponent],
  template: `
  <div>
    condition: 
    <input type="checkbox" (change)="condition = !condition"> {{condition}}
  </div>

  <hr>
  With condition:
  <test-projection>
    @if(condition) {
      <div>I am projected</div>
    }
  </test-projection>

  <hr>
  Without condition:
  <test-projection>
     <!-- Nothing -->
  </test-projection>

  <hr>
  Static:
  <test-projection>
  Something
  </test-projection>
`,
})
export class Playground {
  condition: boolean = false;
}

Please provide a link to a minimal reproduction of the bug

https://stackblitz.com/edit/6h4pbxhv?file=src%2Fmain.ts

Please provide the environment you discovered this bug in (run ng version)

Tested with Angular 19 & 20

Anything else?

Something else may be going on. I am not sure if it the same issue or cause, but in the following example with nested @if:

@Component({
  selector: 'test-projection',
  standalone: true,
  template: `
    Projected [content]:
    <ng-content select="[content]">Fallback [content]</ng-content>

    <hr>
    Default ngcontent:
    <ng-content>Fallback default</ng-content>
  `,
})
export class ContentProjectComponent {}

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [ContentProjectComponent],
  template: `
  <div>
    Project1: 
    <input type="checkbox" (change)="project1 = !project1"> {{project1}}
  </div>
    <div>
    Project2: 
    <input type="checkbox" (change)="project2 = !project2"> {{project2}}
  </div>
  <hr>
   <test-projection>
     @if (project1) {
       @if (project2) {
         <div content>I am not projected</div>
       }
     }
     @if(project1) {
       <div content>I am projected</div>
     }
   </test-projection>
  `,
})
export class PlaygroundComponent {
  project1: boolean = false;

  project2: boolean = false;
}

When both project1 and project2 are true, the "I am not projected" is rendered inside the default ng-content and not the [content] one.
Obviously here no fallback is ever rendered.
Looks related to #54035 but there is no mention of fallback content there so I guess it is a combination of both problems in this case.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions