`@HostListener` is not limited to methods — it is equally valid on a property
holding a function, which is the idiomatic way to keep `this` bound:
@HostListener('window:beforeunload', ['$event'])
private onUnload = (event: BeforeUnloadEvent) => {...};
Every existing host-listener compliance case declares the handler as a method,
so the property form was uncovered. This adds a case exercising both a public
and a private function-valued property, one of them with a global (`window:`)
event target, and locks in the emitted chained `ɵɵlistener` calls plus
`ɵɵresolveWindow`.
Verified against all four compliance modes (full, partial/linked,
declaration-only); GOLDEN_PARTIAL.js regenerated via the golden update rule.
(cherry picked from commit d44b3224d9)
Host binding sanitization previously used the declaring directive or component selector to choose a compile-time security context. The same host binding can execute on a different concrete element through hostDirectives, inherited host bindings, dynamic directives, or createComponent hostElement usage.
Compute host binding security contexts against possible concrete hosts and defer URL versus ResourceURL selection to runtime when necessary. Resolve dynamic root host TNodes to their native tag before sanitizer and security-sensitive attribute checks.
Fixes angular#69550
PR Close#69558
Reformats the TEST_CASES.json files touched by the following change so they
satisfy the repo's prettier check (short inputFiles/files arrays collapsed to a
single line). Pure formatting; the parsed JSON is unchanged. Split into its own
commit so the coverage change that follows is easy to review.
(cherry picked from commit 5245ca5ba7)
Adds a compliance case pinning the instruction-set selection for a
directive-free standalone component:
- full compile: the compiler can prove the template has no directive
dependencies, so it takes the DOM-only fast path
(`ɵɵdomElementStart`/`ɵɵdomElementEnd`).
- local compile: the compiler cannot inspect dependencies, so
`hasDirectiveDependencies` is forced true and the full instruction
set is emitted (`ɵɵelementStart`/`ɵɵelementEnd`).
This mode-dependent switch was previously only exercised incidentally by
the `foreign_component` case, which couples it with foreign-component
compilation. The new case isolates it.
(cherry picked from commit eb3e480360)
The AnimationClassBindingFn type was too restrictive, only allowing `string | string[]`. However, the runtime (`getClassListFromValue`) safely handles `undefined` and `null` values by treating them as no animation.
This change updates the type to allow `undefined` and `null`, which is consistent with other class/style bindings in Angular and avoids requiring workarounds (like empty strings) in host bindings.
Added a compliance test case to verify that `[animate.enter]` with a potentially `undefined` value compiles correctly.
(cherry picked from commit a7bde662c3)
Adds support for `@Input` transform functions in isolated declarations mode (`emitDeclarationOnly: true`), allowing components and directives to specify `transform` functions without triggering fatal compiler errors.
Synthesizes the `ngAcceptInputType_` write type syntactically:
- For referenced functions (`transform: booleanAttribute`), emits `Parameters<typeof booleanAttribute>[0]`, relying on downstream template type checking to resolve the type.
- For inline functions (`transform: (v: string) => boolean`), extracts `parameters[0].type` directly from the local TypeScript AST.
(cherry picked from commit 86ade07de6)
Removes restrictions around using external references and local directives in `hostDirectives` under isolated declarations mode (`emitDeclarationOnly: true`).
By wrapping the host directive reference in a `WrappedNodeExpr`, TypeScript's declaration emitter seamlessly emits `typeof hostReference.node`, preserving existing imports or local identifiers exactly as authored. Also adds support for translating `PropertyAccessExpression` inside `WrappedNodeExpr` into `QualifiedName` for `.d.ts` emission, ensuring namespace imports (`import * as n from './dir'`) are preserved correctly.
(cherry picked from commit 5d2b1c4100)
An abstract component or directive can extend another class, meaning
ɵɵgetInheritedFactory needs to allow abstract
(cherry picked from commit 2112edefe1)
d1539a8513 incorrectly assumed components wouldn't be abstract but
it is still possible (though probably should be an abstract directive instead).
(cherry picked from commit 8984c59626)
Apply schema-derived sanitizer resolution to TwoWayProperty ops so native two-way DOM bindings emit the same sanitizer as one-way property bindings.
Add compiler compliance coverage for innerHTML, srcdoc, URL, resource URL, and security-sensitive attribute cases.
(cherry picked from commit 3c70270c96)
Currently we only skip regex optimization if it has the `g` flag, however regexes can also have a state with the `y` flag.
These changes move to an allowlist model where we only optimize for a set of know flags.
(cherry picked from commit 636cc94105)
There was not a test demonstrating local compilation with the
'bootstrap' param on NgModule. This test adds one, among other NgModule
fields in one. These other fields are broadly covered already, but this
rolls them into one test exercising all fields.
This commit updates `@defer` logic related to incremental hydration to be tree-shakable.
If hydrate triggers are used in a `@defer` block, the compiler emits a single top-level call to `ɵɵenableIncrementalHydrationRuntime`, placed once per create block before the first `ɵɵdefer` that requires it.
As a result, the incremental hydration runtime is only included in the bundle when hydrate is explicitly used.
These changes introduce the new `@Service` decorator which is a more ergonomic alternative to `@Injectable`. The reason we're adding a new decorator is that `@Injectable` has been around since the beginning of Angular and it has a lot of baggage that adds unnecessary overhead for users that generally want to define a singleton service, available in their entire app. The key differences between `@Service` and `@Injectable` are:
1. `@Service` is `providedIn: 'root'` by default. You can opt into providing the service yourself by setting `autoProvided: false` on it.
2. `@Service` doesn't allow constructor-based injection, only the `inject` function.
3. `@Service` doesn't support the complex type signature of `@Injectable` (`useClass`, `useValue` etc.). Instead it supports a single `factory` function.
Example:
```ts
import {Service} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {AuthService} from './auth';
@Service()
export class PostService {
private readonly httpClient = inject(HttpClient);
private readonly authService = inject(AuthService);
getUserPosts() {
return this.httpClient.get('/api/posts/' + this.authService.userId);
}
}
```
Fixes that we were parsing bindings in the `host` object with a regex that didn't account for nested brackets which may come up with something like Tailwind.
Fixes#68039.
Implement support for `FormUiComponent`s in both Reactive and Template-driven
forms. This allows components that use the new signal-based form control
architecture to be used seamlessly within existing Angular form paradigms.
Key changes:
- Integrated `ɵngControlCreate` and `ɵngControlUpdate` lifecycle hooks into
`NgModel`, `FormControlDirective`, and `FormControlName`.
- Implemented branching logic to choose between the traditional `ControlValueAccessor` (CVA) path and the new FVC path based on the host element's capabilities.
- Added comprehensive unit tests for FVC integration in both Reactive (`reactive_fvc.spec.ts`) and Template-driven (`template_fvc.spec.ts`) forms, covering:
- Value synchronization (model -> view and view -> model).
- Status synchronization (touched, dirty, valid, invalid, pending, required).
- Error propagation and `parseErrors` support.
- Fallback behavior to native DOM properties (disabled, required) when FVC inputs are missing.
- Graceful fallback to CVA when no FVC pattern is detected.
- Refined `NgModel` to correctly handle `required` validation via its existing `RequiredValidator` directive while supporting FVC for other properties.
The Angular compiler unconditionally adds a debug name transform for signals
which generates a conditional on `ngDevMode` (e.g., `ngDevMode ? { debugName: "xyz" } : []`).
During testing, `ngDevMode` is true, so the true branch executes but the
false branch is never executed. Consequently, coverage tools report the
false branch as an untested line/branch, preventing 100% test coverage.
This commit adds a synthetic `/* istanbul ignore next */` comment to the
generated false branch so that Istanbul ignores it. We only include the
istanbul comment (instead of additionally including c8) to focus on the
established standard for Angular CLI/Karma coverage while maintaining
compatibility with modern Vitest setups, since @vitest/coverage-v8 now
natively respects the fallback istanbul comment.
Fixes#64583
Allows specifying a timeout parameter for idle-based deferred triggers, enabling more granular control over when deferred actions are executed.
Closes angular#67187
inputs & outputs cannot be binded to 2 different directives/components properties
Eg
```
data = model();
dataChange = output(); // throws because model already emits on the `dataChange` output
userSomething = input({alias 'user'});
user = input(); // throws because userSomething already binds to the `user` input
````
fixes#65844
BREAKING CHANGE: The compiler will throw when there a when inputs, outputs or model are binding to the same input/outputs.
Refactors the `ɵɵcontrolCreate` and `ɵɵcontrol` instructions to delegate control logic to the forms package via new `ɵngControlCreate` and `ɵngControlUpdate` lifecycle hooks. Previously, the logic for binding form state to native elements and custom controls was hardcoded within `@angular/core`.
**Compiler Changes:**
- Introduces a new compilation phase `specializeControlProperties` (in `control_directives.ts`).
- This phase detects properties named `formField` and specializes them into `ControlCreate` and `Control` IR opcodes.
- These opcodes emit `ɵɵcontrolCreate` and `ɵɵcontrol` instructions, respectively.
**Runtime Changes:**
- `ɵɵcontrolCreate` acts as the creation phase. It locates the control directive and invokes its `ɵngControlCreate` method.
- `ɵɵcontrol` acts as the update phase, and invokes the control directive's `ɵngControlUpdate` method (if present).
- Introduces a `passThroughInput` configuration in `ControlFeature`. This specifies the input name (e.g., `formField`) that triggers the control. If the runtime detects that this input is bound to multiple targets (e.g., the `FormField` directive *and* the host component), the control is flagged as "pass-through". In this state, `ɵngControlCreate` returns a no-op update function, deferring responsibility to the other consumer (e.g., the component managing the field itself).
**Forms Changes:**
- `FormField` directive implements `ɵngControlCreate` and `ɵngControlUpdate`.
- Inside this hook, `FormField` determines the type of control it is attached to (Native, CVA, or Custom Signal Control) and delegates to the appropriate handler (`nativeControlCreate`, `cvaControlCreate`, or `customControlCreate`).
- Consolidates all form binding logic within `@angular/forms/signals`, enabling support for new `FormValueControl` and `FormCheckboxControl` interfaces.
- Reorganizes the codebase by moving `FormField` from `api/` to `directive/` and splitting the binding logic into semantic pieces:
- `control_native.ts`, `control_cva.ts`, and `control_custom.ts` contain the specific handlers for each control type.
- `native.ts` and `select.ts` provide helpers for native element discovery and select-specific synchronization.
- `bindings.ts` manages the tracking and application of property/attribute bindings.
When producing a listener, the template pipeline does the following in separate phases:
1. Generates all the variables available within its scope.
2. Adds `restoreView` and `resetView` calls if there are any referenced to local variables (e.g. `@let` or local refs).
3. Optimizes away the variables that aren't used.
This means that we can end up in a situation where the references to the variables in the scope no longer exist, but we still enter and leave the view as if they're there which is unnecessary.
These changes add a simple optimization pass that looks specifically for the pattern of a `restoreView` followed by a `return resetView(expr)`. Furthermore, by changing the order of some optimizations, we're able to drop the `getCurrentView` variable as well.
Fixes#66286.
```ts
@Component(...)
class Outer {
constructor() {
@Component(...)
class Inner {}
}
}
```
previous behavior was that IVy transformation was only applied to `Inner`, thus breaking `Outer` transformation.
Prior to this change, binding to radio value was sensitive to the order in which `value` & `formField` where binding in the template.
The compiler change makes that order non-important.
fixes#66402
This completes the rename started in #66136. `[field]` is too generic of
a selector for the forms system to own, and likely to cause naming
collisions with existing components. Therefore it is being renamed to
`[formField]`
Reworks how we store arrow functions in the following ways:
1. Rather than the `storeCallback` and `getCallback` instructions, we generate a single `arrowFunction` instruction.
2. The `arrowFunction` instruction uses a factory to create a new instance of the function when a function is read for the first time.
3. We now keep arrow functions in listeners in line so that they have access to `$event`.
Adds support for using arrow functions in Angular expressions. They generally behave like JS arrow functions with the same access as other Angular expressions, but with the following limitations:
* We only support arrow functions with implicit returns, e.g. `(a) => a + 1` is allowed while `(a) => { return a + 1 }` is not.
* Pipes can't be used inside arrow functions, but they can be passed through to pipes.
To avoid recreating the functions in each change detection, the compiler applies a couple of optimizations:
* If an arrow function only references its own parameters, it is extracted into a top-level constant that is passed around to the different usage sites.
* If an arrow function has references to the template context, we store it on the current view and read the stored value later on.
Fixes#14129.