The open_in_new icon on external navigation items stayed grey on hover
and sat inset from the chevron column, so it never matched the chevron
items visually.
- Add a hover rule so the icon brightens to --primary-contrast along
with the label, matching the chevron/text behaviour.
- Override the 1rem max-width reserve inherited from
.docs-faceted-list-item-text by chaining both classes the span carries
(.docs-external-link.docs-faceted-list-item-text), so the icon lines up
with the chevrons at the link's end-padding. Using :host was avoided
because it breaks the nested `a:hover &` selector.
Update the `headerRule` regex to capture the complete quoted header value. The previous pattern excluded quote characters from the content and failed to parse headers such as:
```angular-ts {avoid, header: "Can't inject interface"}
```
The new pattern matches everything between the opening and closing quote delimiters.
Enable foreign components to receive and propagate contextual data
across framework boundaries.
Previously, foreign render functions only accepted component properties,
and foreign content projection instructions (`ɵɵforeignContent` /
`ɵɵforeignContentFn`) did not provide any mechanism to expose foreign
framework context to projected Angular embedded views.
With this change:
- Update `ForeignRenderFn` and `ForeignComponent` interfaces to accept
an optional context parameter and an optional `GET_CONTEXT` symbol
method.
- Introduce `FOREIGN_CONTEXT` injection token and
`provideForeignRootContext` helper to configure root context in
Angular's DI hierarchy.
- Update `ɵɵforeignComponent` instruction to resolve `FOREIGN_CONTEXT`
from the injection tree and pass it to the foreign component's render
function.
- Update `ɵɵforeignContent` and `ɵɵforeignContentFn` instructions to
wrap embedded view creation with a `ForeignContextInjector` when
`GET_CONTEXT` is present.
Furthermore, foreign render functions are no longer run inside an
Angular injection context, since it's expected they use the foreign
context support directly.
PR Close#69502
The `myForm` field is a callable `FieldTree`, so its value must be read
via `this.myForm().value()`. Fixes two examples that incorrectly used
`this.myForm.value()`.
the toSignal function received a debugName option in 0812ac3bec,
but was not covered by the signalMetadataTransform which sets the debugName in dev mode
automatically.
Transition parameterless `@content` projection in foreign components
from eager DOM creation to lazy evaluation. Previously, projecting
content into a foreign component eagerly instantiated the embedded view
and created DOM nodes, causing unnecessary resource consumption if the
content was hidden or unmounted.
With this change, runtime content instructions (`ɵɵforeignContent` and
`ɵɵforeignContentFn`) pass lazy producer callbacks directly through the
foreign component's configured `contentAdapter`. View creation and
teardown registration occur lazily when the external framework evaluates
the adapted producer.
`foreignImport` now requires a third argument, `contentAdapter`,
specifying how Angular content producer callbacks are adapted for the
target external framework.
Update and streamline the Model Context Protocol (MCP) server setup guide. This includes revising tool descriptions, replacing multiple experimental tools with a single target runner option, updating configurations for supported IDEs, and removing obsolete setup sections.
The Aria menubar examples render each menu in a `cdkConnectedOverlay`,
which detaches the top-most overlay on every Escape keypress
(`disableClose` defaults to `false`). The top-level menus are always
attached, so a detached overlay never reattaches and its `viewChild`
reference becomes `undefined`. Holding Escape detaches the overlays one by
one, permanently breaking menus such as "Insert" and "Format".
Set `cdkConnectedOverlayDisableClose` on the example overlays so the menu
pattern remains the single owner of open/close state, matching the
combobox and toolbar examples. Applied to the basic, disabled, and rtl
menubar examples (and their material/retro variants).
Currently, signal migration schematics in best effort mode doesn't do a very good job migrating input writes when there is a nested property access in templates.
In event handlers, no attempt is made to migrate a nested access in the left-hand-side of assignments or anything in their right-hand-side. E.g., nothing will happen here:
`(ngModelChange)="inputD.prop = $event + inputF"`.
Additionally, when a migration attempt is made, parentheses are often incorrectly placed on the parent, both in event handlers and two-way bindings:
`(ngModelChange)="inputC = $event"` is migrated to `(ngModelChange)="inputC = $event()"`.
`[(ngModel)]="inputB.prop.prop"` is migrated to `[(ngModel)]="inputB.prop().prop"`.
When `rootDir` was set in a project's tsconfig (e.g. `rootDir: "src"`),
tsurge-based migrations would fail because `projectRoot` was derived from
`rootDir`, causing `rootRelativePath` to be computed relative to `src/`
instead of the workspace root. This produced paths like `app/app.ts`
instead of `src/app/app.ts`, which the DevKit tree could not resolve.
Fix by overriding `info.projectRoot` to `absoluteFrom(info.program.getCurrentDirectory())`
immediately after program creation, ensuring workspace-relative paths are
used for all tree updates.
When partial declarations are not preprocessed to AOT by the linker, the `ngDeclareComponent`
call causes them to be compiled ad-hoc. In this mode, NgModule imports in standalone components
would be dropped, deviating from the linker. This commit changes the ad-hoc compilation of
component declarations to pass the NgModule imports along just like the linker does.
Fixes#69451
Initialize `zoneSymbolEventNames` and `patches` with `Object.create(null)` instead of `{}`.
This is a hardening change rather than a fix for an exploitable vulnerability. Calling `addEventListener('__proto__', fn)` is not directly attacker-controlled; its presence already implies an application bug. However, if such a call does occur, the current implementation can behave unexpectedly depending on the environment.
For `zoneSymbolEventNames`, accessing `zoneSymbolEventNames['__proto__']` on a plain object invokes the inherited `__proto__` accessor and returns `Object.prototype`, which is truthy. This causes `prepareEventNames()` to be skipped, leaving `symbolEventName` undefined and eventually leading to a runtime error when `window['undefined'] = []` is executed.
In Node.js environments running with `--disable-proto=throw`, the assignment:
```ts id="z8n4qm"
zoneSymbolEventNames['__proto__'] = {};
```
throws immediately because it triggers the disabled `__proto__` setter.
The `patches` registry has a similar issue. A `__proto__` key passed to `__load_patch()` bypasses the duplicate-patch check and reaches:
```ts id="f3v7kx"
patches['__proto__'] = fn(...);
```
which invokes the `__proto__` setter and changes the prototype of the `patches` object.
Using `Object.create(null)` removes the inherited `__proto__` accessor entirely, causing these keys to behave like ordinary properties rather than interacting with JavaScript's prototype machinery.
As part of this change, `patches.hasOwnProperty(name)` is also updated to:
```ts id="n2c8wp"
Object.prototype.hasOwnProperty.call(patches, name)
```
since null-prototype objects do not inherit `hasOwnProperty`.
`model()` signals are special because they combine a signal input with a writable output through an internal `OutputEmitterRef`. During upgrade, `setupOutputs()` subscribes to that emitter to keep Angular → AngularJS two-way binding working.
The issue was that `updateInput()` could overwrite the signal property directly when `isSignal` was `false` (which happens in JIT mode and when `unsafelyOverwriteSignalInputs` is enabled). Once that happened, the original `OutputEmitterRef` was lost, so the two-way binding stopped working.
The fix detects `model()` signals at runtime by checking for both `[SIGNAL]` and a writable `.set()` method, which distinguishes them from read-only `input()` signals. When those traits are present, updates are always applied through `applyValueToInputSignal()` instead of replacing the property directly, regardless of the `unsafelyOverwriteSignalInputs` setting.
Fixes#60599
Without this change, components that use RouterLinkActive in multiple
contexts (e.g. both a navigation menu and body content) are forced to
branch the template for every conditional input:
@if (activeClass) {
<a [routerLink]="href" [routerLinkActive]="activeClass"
[routerLinkActiveOptions]="activeOptions"
[ariaCurrentWhenActive]="ariaCurrent">
<ng-content />
</a>
} @else {
<a [routerLink]="href"><ng-content /></a>
}
Every additional input multiplies the branching, and each @if/@else
injects unwanted comment nodes into the DOM. There is no way to
conditionally attach a directive in Angular templates, making imperative
TypeScript instantiation the only alternative.
Accepting null/undefined collapses this to a single template branch:
<a [routerLink]="href"
[routerLinkActive]="activeClass"
[routerLinkActiveOptions]="activeOptions"
[ariaCurrentWhenActive]="ariaCurrent">
<ng-content />
</a>
When activeClass is undefined (e.g. in content areas), the directive
stays mounted but applies no CSS classes. When it is a string (e.g. in
the navigation), normal active-class behavior applies — no branching, no
extra DOM nodes, no TypeScript workarounds.
- `routerLinkActive`: null/undefined now sets an empty class list.
- `routerLinkActiveOptions`: null and undefined are treated differently:
- undefined → falls back to the default subset match ("not set")
- null → explicit opt-out, link is never considered active
Closes#66233
Preserve explicit referrer policy when the service worker reconstructs asset requests for cache-busted and redirected asset fetches.
For example, an application can load a script or image with referrerPolicy: 'same-origin' or 'origin' to limit referrer data. Dropping that policy can expose more of the current URL to that resource host.
Preserve referrer metadata when the service worker reconstructs asset requests for cache-busted and redirected asset fetches.
For example, an attacker with access to asset host logs could receive a reset token embedded in a page URL if the reconstructed request falls back to default referrer behavior instead of carrying referrer: ''.
`parseHostBindings` throws plain `Error`s for malformed host bindings
(e.g. a property binding with a non-static value, as can happen while
editing in the language service). These were uncaught during directive
analysis, crashing the compiler and the Angular Language Service.
Wrap the call and surface the error as a `FatalDiagnosticError` so it
becomes a diagnostic and analysis can complete normally.
Fixes#69106
A custom FormValueControl only participates in debounce('blur') if it emits
the touch output on the native blur event. This was undocumented, and the
touch name reads like a focus event, so users wired it to (focus) and
blur-based debouncing silently did nothing.
Add a dedicated guide section with a working example, link the debounce API
reference to it, and clarify the touch JSDoc that it must fire on blur, not
focus.
Fixes#69370
Explain that MIN and MAX are selection keys which point to the type-specific limit metadata keys, such as MIN_NUMBER, MIN_DATE, MAX_NUMBER, and MAX_DATE.
Also list minDate() and maxDate() alongside min() and max() in the Signal Forms metadata docs, so the validator tables match the actual metadata model.
Adds a 'Chaining resources' section to the resource guide covering:
- Basic usage of chain() to depend one resource on another
- Status propagation for all ResourceStatus values (idle, loading,
reloading, error, resolved, local)
- Chaining vs reading .value() directly, shown as an avoid example
- Guidance on passing the chained value directly as params
Also adds an @see link from ResourceParamsContext to the new section.
Closes#69329
Adds an error reference page for NG05102 (UNSUPPORTED_EVENT_TARGET) explaining
what triggers it and how to fix it. Also marks the error code as negative (-5102)
so that in dev mode the error message automatically links to the new guide page
on angular.dev/errors, consistent with other documented runtime errors.
Skip HttpTransferCache serialization for HTTP responses that contain a
Set-Cookie header.
Cookie-setting responses commonly represent session-specific,
user-specific, or security-sensitive state. Serializing their bodies into
SSR TransferState can embed sensitive data into the generated HTML, where
it may be reused during hydration or replayed by a shared cache/CDN.
- Rename `DirectiveForestHooks` to `DirectiveForestManager`
- Keep profiler reference standalone; move it out from `DirectiveForestHooks`/`DirectiveForestManager`
- Convert profiler-specific `IdentityTracker` behavior to a more generalized one
- Separate timing API functionality from the `DirectiveForestHooks`/`DirectiveForestManager` initialization fn
- Reorganize files; rename `/hooks` to `/profiling`
- Use concrete types for directive and component instances (incomplete coverage; based on `any` at the moment)
- Other more minor changes
The "Community translations" column heading wrapped to two lines while
the other footer headings stayed on one. Add a `white-space: nowrap`
rule on the footer headings, scoped to the wide (4-column) layout. The
breakpoint is driven by a shared `$columns-breakpoint` variable so the
nowrap rule and the grid's 2-column collapse stay in sync.
Update the security guide to document that the Angular SSR request handling pipeline now supports and validates the standard RFC 7239 `Forwarded` header.
Previously, only non-standard `X-Forwarded-*` headers were supported for resolving proxy-forwarded protocols, hosts, and ports. With this update:
- The standard `Forwarded` header parameters (such as `host` and `proto`) are validated and take precedence over corresponding `X-Forwarded-*` headers when trusted.
- The `trustProxyHeaders` option and `NG_TRUST_PROXY_HEADERS` environment variable can be configured to trust the `Forwarded` header.
For more details on the implementation, see the corresponding PR:
https://github.com/angular/angular-cli/pull/33406
Fixes a minor issue where the `preload` function in `injectAsync` might cause an uncaught promise error.
I also fixed that in `onIdle` we were passing the wrong function into `assertInInjectionContext`.