Skip to content

fix(compiler): check @defer blocks in the control flow content projection diagnostic - #71398

Open
aminesbdev wants to merge 1 commit into
angular:mainfrom
aminesbdev:fix/compiler-ng8011-defer
Open

aminesbdev wants to merge 1 commit into
angular:mainfrom
aminesbdev:fix/compiler-ng8011-defer

Conversation

@aminesbdev

Copy link
Copy Markdown
Contributor

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • angular.dev application / infrastructure changes
  • Other... Please describe:

What is the current behavior?

The content of a @defer block always goes to the default ng-content slot, because the block doesn't copy the tag name and attributes of its root node (#58110, tracked in #64504). NG8011 doesn't check @defer blocks, so this happens without any warning:

<app-card>
  @defer {
    <h2 card-title>Title</h2>
  }
</app-card>

<h2 card-title> is projected into the default slot instead of [card-title], or not rendered if the component has no default slot.

Issue Number: Fixes #71397

What is the new behavior?

TcbControlFlowContentProjectionOp also goes through the @defer blocks of the element, including their @placeholder, @loading and @error blocks, and reports each root node that matches a specific slot. Unlike the other blocks, a single root node is reported too, since it isn't projected either.

The suggestions in the existing message (keep a single root node) don't apply here, so the out-of-band recorder gets a separate deferredBlockPreventingContentProjection method. It uses the same error code and the same controlFlowPreventingContentProjection option, and points to ngProjectAs:

Node matches the "[card-title]" slot of the "Card" component, but will not be projected into the specific slot because it is inside a @defer block. The content of @defer blocks, including their @placeholder, @loading and @error blocks, is always projected into the default slot, or not rendered if the component doesn't have one. To project the node in the right slot, wrap the @defer block in an <ng-container/> with an "ngProjectAs" attribute that matches the "[card-title]" selector.

I added four tests: the main block, the secondary blocks, content that only matches the catch-all slot, and the ngProjectAs workaround. The two that expect a diagnostic fail without the change. Like the other specs of this diagnostic, they're listed in ngp_known_failures.ts.

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

The generated code doesn't change. The new warning only shows up for a @defer block placed directly inside a component with ng-content selectors, when one of its root nodes matches a specific selector. That node is already in the wrong slot today, so each warning points to a real bug, but it can be new on code that compiles cleanly now. If that's a problem for the internal rollout, I can retarget the PR.

🤖 Generated with Claude Code

@pullapprove
pullapprove Bot requested a review from atscott October 16, 2026 16:57
@angular-robot angular-robot Bot added the area: compiler Issues related to `ngc`, Angular's template compiler label Oct 16, 2026
@google-cla

This comment was marked as outdated.

@ngbot ngbot Bot added this to the Backlog milestone Oct 16, 2026
…ection diagnostic

The content of a `@defer` block is always projected into the default slot,
because the block doesn't copy the tag name and attributes of its root node
like `@if`, `@for`, `@switch` and `@boundary` do. The
`controlFlowPreventingContentProjection` diagnostic (NG8011) didn't look at
`@defer` blocks, so a node matching a specific `ng-content` selector ended up
in the default slot, or wasn't rendered, without any warning.

The diagnostic now reports the root nodes of `@defer` blocks, including their
`@placeholder`, `@loading` and `@error` blocks, even when there is a single
root node. The message points to `ngProjectAs`, since keeping a single root
node doesn't help for `@defer` blocks.

Fixes angular#71397
@aminesbdev
aminesbdev force-pushed the fix/compiler-ng8011-defer branch from 3daab79 to 4b3c07c Compare October 16, 2026 17:09
@JeanMeche
JeanMeche removed the request for review from atscott October 16, 2026 17:51
@JeanMeche JeanMeche assigned JeanMeche and unassigned JeanMeche Oct 16, 2026
@pullapprove
pullapprove Bot requested a review from atscott October 16, 2026 17:51
@JeanMeche
JeanMeche requested review from JeanMeche and removed request for atscott October 16, 2026 17:51
@JeanMeche JeanMeche added the requires: TGP This PR requires a passing TGP before merging is allowed label Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: compiler Issues related to `ngc`, Angular's template compiler requires: TGP This PR requires a passing TGP before merging is allowed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NG8011 isn't reported when a @defer block prevents a node from being projected

2 participants