533 Commits

Author SHA1 Message Date
Kristiyan Kostadinov 77e2a2a85c refactor(core): expose onDestroy in DirectiveFixture
Exposes the `onDestroy` method from the host component in `DirectiveFixture`. We need this for harnesses in the CDK.
2026-09-09 16:11:33 +02:00
Alex Rickabaugh 54ed62d240 refactor(core): implement @boundary runtime primitives and AST nodes (#70463)
Add the runtime primitives `ɵɵboundaryCreate` and `ɵɵboundaryUpdate` to
the core instructions, which handle synchronous view destruction and
provide the `ON_ERROR` interceptor hooks.

Also include the initial compiler AST representations for the new syntax
including the Lexer tokenization and HTML Parser integration. This lays
the foundational structure for `@boundary` prior to code generation.

Co-authored-by: Matthieu Riegler <kyro38@gmail.com>

PR Close #70463
2026-09-09 15:56:05 +02:00
Alex Rickabaugh f6afb807c1 feat(core): add ErrorBoundary programmatic APIs (#70463)
Implement error interception during refreshView and provide onError callback options in ViewContainerRef for programmatic rendering and encapsulation of boundary errors.

PR Close #70463
2026-09-09 15:56:05 +02:00
Andrew Scott caeab598c9 refactor(compiler): emit any as type argument for ɵɵInjectableDeclaration
The static `ɵprov` field emitted on `@Injectable()` classes uses `ɵɵInjectableDeclaration<T>`.
When a subclass extends a generic `@Injectable()` base class with contravariant parameters
(such as callback/transformer methods depending on generic type parameters), TypeScript's
static side inheritance check (`typeof Sub extends typeof Super`) fails with `TS2417` because
`ɵɵInjectableDeclaration<Sub>` is not assignable to `ɵɵInjectableDeclaration<Super<any>>`.

Using `any` (`o.DYNAMIC_TYPE`) in `createInjectableType` avoids strict variance checks on
static inheritance for internal Ivy definitions and aligns with other Ivy declaration types.
2026-09-04 07:05:23 -07:00
Kristiyan Kostadinov 05c4d5a835 feat(core): add utility for testing directives
Adds `TestBed.createDirective` to make testing directives easier.

Fixes #54164.
2026-09-01 14:40:05 -07:00
Doug Parker 91a2bf8425 feat(core): support annotations in WebMCP tool declarations
This updates `declareExperimentalWebMcpTool` to allow annotations to be provided to opt-in the tool explicitly into being read only or returning untrusted content.
2026-09-01 09:39:20 -07:00
arturovt 8975b4346d docs: add NG0991 error page and document rxResource's completion contract
RESOURCE_COMPLETED_BEFORE_PRODUCING_VALUE had no guide, no JSDoc on
RxResourceOptions.stream, and — since the code was positive rather
than negative — could never get an auto-linked docs page even if one
existed. Flip it to -991, add the NG0991 reference page, and document
the "stream must emit a value or an error before completing"
requirement on stream's JSDoc and in the RxJS interop guide.

Also documents and tests that an unguarded template read of an
errored resource's .value() propagates to the global ErrorHandler,
and recommends guarding with .hasValue() as defense in depth.

httpResource can throw the same error, but for a different reason:
its internal request Observable isn't something app code writes
directly, so an empty completion there is almost always an
HttpInterceptor swallowing the response (catchError(() => EMPTY))
rather than a stream authored in the resource() call itself. The page
covers both APIs with guidance matched to what's actually going on
for each.
2026-09-01 09:31:00 -07:00
arturovt 83f7695b2e fix(core): throw coded RuntimeErrors instead of crashing when hydration/rendering can't find an expected DOM node
This started from a real production crash trace:

    TypeError: Cannot read properties of null (reading 'nextSibling')

Traced through a minified bundle back to siblingAfter() in
packages/core/src/hydration/node_lookup_utils.ts. It walks forward a
fixed number of DOM siblings during hydration, based on how many the
server rendered. Its only guard, validateSiblingNodeExists(), is
gated behind ngDevMode and stripped from production builds. If the
client DOM has fewer real siblings than the server-serialized data
expects — client/server render diverged, or something outside
Angular (a browser extension, an injected script) removed a node —
the loop ran fully unguarded in production: currentNode went null
partway through, and the next iteration's currentNode.nextSibling
threw a raw, uncoded TypeError instead of a coded, debuggable one.

Reproduced first, not just theorized: added a test that server-
renders a @for loop with 3 items, removes 2 of them before hydration
runs, and confirmed it actually throws that exact TypeError against
the original code before touching anything.

Fix: add a null check at the top of the loop, matching the pattern
already used for the existing NG0500/NG0502 hydration checks in
element.ts — the dev-mode check runs first as before (a no-op in
production), and the new check is a pure safety net that only fires
once that dev-mode check has already been compiled away. In dev mode
this is provably dead code, so nothing about dev behavior changes.
Coded as NG0501 (HYDRATION_MISSING_SIBLINGS, already existed).

While investigating, found and fixed two more call sites with the
exact same shape of bug — a dev-only check that leaves production
completely unguarded:

- navigateToNode() (same file): walks an explicit "firstChild /
  nextSibling" navigation path recorded for nodes that can't rely on
  simple sibling-walking (e.g. content right after an <ng-content>
  slot). Its only guard was also ngDevMode-only. Added the same
  production safety net, both mid-loop (the raw-crash case) and
  post-loop (where it could previously return null silently despite
  the function's return type promising a non-null RNode). New code:
  NG0509 (HYDRATION_MISSING_NODE_ON_PATH).

- getParentRElement() (render3/node_manipulation.ts): typed its
  tNode parameter as always non-null, but a real production trace
  showed it can be null at runtime, crashing on tNode.parent with no
  useful information. Widened the type to TNode | null and added a
  guard that throws a coded error instead. New code: NG0510
  (PARENT_NODE_NOT_FOUND).

  Unlike the other two, this one isn't gated behind ngDevMode at all
  in the original code — it reproduces unconditionally. Decoded the
  actual production minified stack trace against this source
  (matched every frame character-for-character) to find the real
  cause instead of guessing: an @if/@switch branch's content is its
  own embedded template with its own TView, built lazily the first
  time that branch renders. If an error interrupts that first pass —
  here, a hydration mismatch on the branch's second child, after the
  first child's TNode was already created — TView.firstCreatePass
  still gets flipped to false in render.ts's `catch` block before the
  error propagates, permanently marking that TView as corrupted.
  Unlike a component's TView (rebuilt from scratch next time via
  getOrCreateComponentTView()'s incompleteFirstPass check), nothing
  rebuilds an embedded view's TView. The next time that exact branch
  is selected again, its instructions read straight from the
  corrupted tView.data instead of creating a fresh TNode, and any
  node past the interruption point is still null.

  The real test added for this (full_app_hydration_spec.ts) exercises
  that whole chain for real: a hydration mismatch on an @if branch's
  second child, then re-entering the same branch. Confirmed it throws
  the exact byte-for-byte production error message ("Cannot read
  properties of null (reading 'parent')") without the fix, and the
  coded NG0510 with it. This replaces an earlier synthetic unit test
  that just cast a variable to null to bypass the type system rather
  than reproducing the actual failure.

  Note: a more thorough fix would rebuild the corrupted embedded TView
  itself (mirroring getOrCreateComponentTView()), which does make the
  crash disappear — but doing that surfaces a second, separate bug:
  the aborted first attempt's partially-created LView/DOM is never
  torn down, so the retried branch's content gets appended alongside
  leftover orphaned nodes instead of replacing them, corrupting
  content silently instead of crashing loudly. That's a materially
  bigger fix (proper LView cleanup after a mid-creation exception) and
  is intentionally out of scope here; this commit keeps the narrower,
  safe fix (a clear coded error) rather than trading a loud crash for
  silent data corruption.

Along the way, deduplicated describeDomNode(), which existed as two
near-identical private copies (one in this file's own NG0500 check,
one in platform-browser's dom_renderer.ts insertBefore check) and
moved it into core's hydration/error_handling.ts, shared via the
private ɵdescribeDomNode export.

That function was then removed from every production code path
entirely, per review feedback: computing a human-readable node
description is debug-oriented work that shouldn't ship unconditionally
in production bundles, regardless of how cheap it is — production
should get the bare coded error only, the same as everywhere else in
this file. All three fixes above follow that: ngDevMode && 'message'
in production, no computed description. Confirmed the removal
actually shrinks output, not just assumed it: regenerated all 8
affected bundling symbol goldens, and each one shows exactly one
symbol removed — "describeDomNode" — and nothing else.
2026-08-25 16:16:22 -07:00
Cameron Smick d45bd2f53d refactor(core): implement toggleWatchSignal for DevTools signal debugging
Implement \`toggleWatchSignal(id)\` in \`signal_debug.ts\` to enable toggling reactive watch listeners on individual signal graph nodes.
- Create reactive \`Watch\` instances using \`createWatch\` to log signal value/state changes to the console when active.
- Use \`WeakRef\` mapping and \`FinalizationRegistry\` (\`watchCleanupRegistry\`) so active watches do not retain strong references to signal nodes or prevent garbage collection.
- Expose \`watched\` status on \`DebugSignalGraphNode\` and publish \`toggleWatchSignal\` onto \`window.ng\` in development mode.
- Add acceptance tests covering watch activation, signal mutation logging, manual disposal, GC cleanup, and safe invalid ID handling.
2026-08-24 15:35:44 -07:00
Kristiyan Kostadinov c18261f3fd build: enable stableTypeOrdering tsconfig flag
`stableTypeOrdering` was recently enabled in the internal builds. While there aren't any breakages in Angular, these changes enable it so we can catch potential issues earlier.
2026-08-24 10:27:15 -07:00
splincode e43eb96341 fix(core): warn when style property bindings receive invalid values
Report unsupported style property binding values in development mode while preserving existing binding behavior. Unwrap trusted style values before appending unit suffixes and link NG0318 warnings to the corresponding error guide.
2026-07-30 09:05:46 -07:00
cexbrayat 0ae6d81ed2 fix(core): preserve explicit input transform write type
If a directive has an input declared as `dismissible = input<boolean>(true, {transform: booleanAttribute});` then the following templates were not compiling:

```
<div directiveName dismissible="true"></div>
<div directiveName dismissible></div>
```

This commit fixes the issue, without breaking contravariant consumers.
2026-07-15 12:02:18 -07:00
Doug Parker f908140d71 refactor(core): update WebMCP tool registration to be asynchronous
In the latest WebMCP specification and Chromium preview builds, `document.modelContext.registerTool` was updated to be asynchronous and return a `Promise`: https://groups.google.com/a/chromium.org/g/chrome-ai-dev-preview/c/xQWt0b1sZIE/m/UJznbNCIAwAJ?utm_medium=email&utm_source=footer

This commit update adjusts Angular's experimental WebMCP implementation (`declareExperimentalWebMcpTool` and form registration) to be async as well, returning `Promise<void>`.
2026-07-10 10:56:41 -07:00
Matthew Beck 1fb4678207 Revert "fix(core): allow static attributes for explicit input transforms"
This reverts commit 9b9b0e93c9.

This broke g3. Not sure yet why it didn't break externally. We can
investigate and fix following this revert.
2026-07-09 17:58:22 -07:00
cexbrayat 9b9b0e93c9 fix(core): allow static attributes for explicit input transforms
This is a follow-up to #67997, which allowed explicit read generics with input transforms, such as `input<boolean>(false, {transform: booleanAttribute})`.

That fixed the declaration, but static template attributes like `dismissible="true"` and bare `dismissible` were still checked as strings against the read type. Allow the fallback write type to include static attribute strings so these template forms compile.
2026-07-09 12:28:25 -07:00
Cameron Smick ae6d8dae75 refactor(core): add childSignalProp to ReactiveNodeKind
Add `childSignalProp` to `ReactiveNodeKind` in order to consolidate `ReactiveNodeKind` types and enable Client-Only Wiz to use it.
2026-06-17 13:03:13 -07:00
cexbrayat c121407c0d fix(core): require WebMCP tool descriptions
The WebMCP ModelContextTool dictionary marks description as required: https://webmachinelearning.github.io/webmcp/#modelcontexttool-dictionary
2026-06-09 10:29:11 -07:00
Alex Rickabaugh 124ba10ead feat(core): add custom set option to linkedSignal
Introduce a custom `set` option in `linkedSignal` options to allow overriding and customizing the default write-back behavior of writable signals. This lets developers route updates back to the source of truth (e.g., converting Fahrenheit back to Celsius) or perform other side effects like updating properties inside a parent signal.

Additionally, the custom callback receives the standard signal setter as its second parameter (`rawSet`) to allow direct internal mutation if desired.

Fixes #59665

TAG=agy
CONV=addbb5c4-4233-49e8-b844-6f732d7d5c72
2026-05-26 16:01:35 -07:00
Alan Agius 61a97f22e8 fix(core): support prefix-insensitive DOM schema lookups and compile-time i18n attribute validation
Updates `DomElementSchemaRegistry` to strip `:svg:` and `:math:` namespace prefixes
from tag names before querying `SECURITY_SCHEMA` at compile-time. This allows SVG
and MathML attributes to correctly match their security contexts during compilation.
2026-05-19 13:00:32 -07:00
Kam 51b1db54ad refactor(core): remove deprecated UNSAFE_IFRAME_ATTRS alias
`UNSAFE_IFRAME_ATTRS` in the `RuntimeErrorCode` enum is a `@deprecated`
alias of `UNSAFE_ATTRIBUTE_BINDING` (same value -910) with no usages
anywhere. Drop it along with the paired
`tslint:disable-next-line:no-duplicate-enum-values` suppression.
`RuntimeErrorCode` is re-exported as `ɵRuntimeErrorCode`, so the
enum's value set is not a stability commitment.
2026-05-18 13:16:02 -07:00
Douglas Parker 38e26f0759 refactor(core): add "experimental" to WebMCP API names.
WebMCP is still an experimental standard and going through frequent changes in the Chrome implementation and the standards process. As a result, we should be clear about the support status of this API and its overall stability guarantees.
2026-05-11 12:43:06 -07:00
Kristiyan Kostadinov c72ebcb1ad fix(core): allow service with factory on abstract classes
Fixes that setting a `@Service` with a `factory` on an abstract class was resulting in a compilation error.
2026-05-08 10:16:15 +02:00
Douglas Parker 3b0ae5fef0 feat(core): add provideWebMcpTools
This is an ergonomic wrapper around `declareWebMcpTool`, allowing a user to define multiple tools directly on an injector's providers, rather than needing to find an injection context.

Example:

```typescript
import {bootstrapApplication, provideWebMcpTools} from '@angular/core';

await bootstrapApplication(RootComp, {
  providers: [
    provideWebMcpTools([
      {
        name: 'hello',
        description: 'Says hello',
        inputSchema: {type: 'object', properties: {}},
        execute: async () => ({content: [{type: 'text', text: 'Hello, World!'}]});
      },
    ]),
  ],
});
```

The `execute` function is invoked in the injection context of the `Injector` it is provided to, meaning you can easily `inject` dependencies and invoke them.

This also works particularly well with route `providers` and `withExperimentalAutoCleanupInjectors`, registering the tools when the router is navigated to and then automatically unregistering them when navigating away. Note that `withExperimentalAutoCleanupInjectors` is required for unregistration to work.

```typescript
import {provideWebMcpTools} from '@angular/core';
import {provideRouter} from '@angular/router';

provideRouter(
  [
    {
      path: '',
      component: Home,
      providers: [
        provideWebMcpTools([
          {
            name: 'hello',
            description: 'Says hello',
            inputSchema: {type: 'object', properties: {}},
            execute: async () => ({content: [{type: 'text', text: 'Hello, World!'}]}),
          },
        ]),
      ],
    },
  ],
  withExperimentalAutoCleanupInjectors(),
);
```
2026-05-06 14:13:20 -07:00
Douglas Parker ef1810197b feat(core): export experimental declareWebMcpTool support
This exports `declareWebMcpTool`, a mechanism for registering WebMCP tools and tying them to Angular's `Injector` lifecycle. This function immediately registers the given tool and automatically unregisters it once the associated `Injector` is destroyed.

This exports the function and all transitively reachable types *except* for JSON Schema types as there are quite a lot and we don't want to couple to this particular implementation will likely be obsoleted by built-in types as the standard develops. If users want to leverage those, they should add their own dependency on `@mcp-b/webmcp-types`.
2026-05-06 14:13:20 -07:00
Matthieu Riegler 5a7c1e62dc feat(core): add ability to cache resources for SSR
This commit adds a `transferCacheKey` option to enable easy caching for `resource`/ `rxResource`.
2026-05-06 09:57:49 -07:00
Matthieu Riegler d7b475122a refactor(core): promote resource & rxResource to stable
The time has come.

Note: #67382 introduced a breaking change where you could notice some sublte timing change on how `value` is set when using `rxResource` or a `stream` on a `resource`
2026-05-05 15:55:25 -07:00
Kristiyan Kostadinov 49748b5c79 fix(core): enforce return type for service factory
Updates the `factory` signature in `@Service` to enforce the type of the returned value.
2026-05-05 09:30:29 -07:00
cexbrayat 1ab654cf28 fix(core): allow explicit read generic with signal input transforms
Using explicit single generic arguments with transforms (for example, input<boolean>(false, {transform: booleanAttribute})) previously failed overload resolution.

Before this fix, type-checking produced:
````
✘ [ERROR] TS2769: No overload matches this call.
  Overload 1 of 5, '(initialValue: boolean, opts?: InputOptionsWithoutTransform<boolean> | undefined): InputSignal<boolean>', gave the following error.
    Type '(value: unknown) => boolean' is not assignable to type 'undefined'.
  Overload 2 of 5, '(initialValue: undefined, opts: InputOptionsWithoutTransform<boolean>): InputSignal<boolean | undefined>', gave the following error.
    Argument of type 'true' is not assignable to parameter of type 'undefined'. [plugin angular-compiler]
```

This change adds specialized overloads for explicit read generics.
2026-05-01 15:53:56 -07:00
Matthieu Riegler bc637a304f refactor(core): add support for default exports to injectAsync
ex:
```
await injectAsync(() => import('./test_service'))
```

We'll be reusing the features that were already used by the router to support components lazy-loading.
2026-04-30 15:53:07 -07:00
Matthieu Riegler 444b024d49 feat(core): Add a injectAsync helper function
The commit introduces a new function to assist users who want to lazy load services and use the DI system to create them.

Example:

```ts
import {injectAsync} from 'angular/core';

class MyCmp {
  someSvc = injectAsync(() => import('..'));

  async onClick() {
    (await this.someSvc()).handleClick();
  }
}
 ```
2026-04-28 12:01:27 -07:00
Kristiyan Kostadinov 8f3d0b9d97 feat(core): introduce @Service decorator
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);
  }
}
```
2026-04-22 11:01:01 -07:00
Matthieu Riegler 4e331062e8 feat(core): allow synchronous values for stream Resources
In order for resources to allow caching in SSR context (eg in the TransferState), resource need to be able to set their value synchronously.

If the resource value is not set synchronously, the resource will be in in a "loading" state which is responsible for destroying the server-hydrated resolved DOM.
2026-04-16 00:13:04 +03:00
Matthieu Riegler f9b74e90e3 refactor(core): simplifying the ComponentFactory usage
The `ComponentFactory` has been removed from the public API in #68055.
This commit continues the cleanup and also removes `ModuleWithComponentFactories` from the public API.
2026-04-13 22:24:18 +03:00
Matthieu Riegler df9eed4ff1 refactor(core): remove ComponentFactoryResolver usages
This API was deprecated for a longtime, and was remove by #68055 from the public API.

We do have alternatives to this old API, so we can entirely remove it to spare some bytes
2026-04-13 16:00:03 +03:00
Matthieu Riegler a0aa8304cd feat(core): bootstrap via ApplicationRef with config
This is to align the shape of the method with `createComponent`

BREAKING CHANGE:The second arguement of appRef.bootstrap does not accept `any` anymore. Make sure the element you pass is not nullable.

fixes #67946
2026-04-07 12:48:53 -07:00
Matthieu Riegler b1f5181ffd refactor(core): remove ComponentFactoryResolver & ComponentFactory from the api surface""
Those APIs date back to pre-ivy times and are long deprecated.

BREAKING CHANGE: `ComponentFactoryResolver` and `ComponentFactory` are no longer available. Pass the component class directly to APIs that previously required a factory, such as `ViewContainerRef.createComponent` or use the standalone `createComponent` function.
2026-04-07 09:30:25 -07:00
Andrew Scott ecae525970 Revert "refactor(core): remove ComponentFactoryResolver & ComponentFactory from the api surface"
This reverts commit 9d76ac8229.
g3 cleanup not complete
2026-04-06 09:24:11 -07:00
Matthieu Riegler 9d76ac8229 refactor(core): remove ComponentFactoryResolver & ComponentFactory from the api surface
Those APIs date back to pre-ivy times and are long deprecated.

BREAKING CHANGE: `ComponentFactoryResolver` and `ComponentFactory` are no longer available. Pass the component class directly to APIs that previously required a factory, such as `ViewContainerRef.createComponent` or use the standalone `createComponentFunction`.
2026-04-02 16:00:57 -07:00
Alex Rickabaugh 24e52d450d feat(forms): add debounce option to validateAsync and validateHttp
This adds support for a `debounce` option to the `validateAsync` and `validateHttp` functions.
This allows developers to debounce the triggering of async validators to improve performance.

A `DebounceTimer` type was also added to `@angular/core` to represent the wait condition parameters uniformly.
2026-03-25 14:17:52 -07:00
Matthieu Riegler 69fb1614ef refactor(core): remove checkNoChanges from the public API.
It's an internal API.

BREAKING CHANGE: `ChangeDetectorRef.checkNoChanges` was removed. In tests use `fixture.detectChanges()` instead.
2026-03-17 13:57:43 -06:00
Andrew Scott dc3131c639 feat(core): TestBed.getFixture -> TestBed.getLastFixture and update implementation
TestBed.getFixture is now TestBed.getLastFixture and returns the last fixture
created rather than throwing if there are more than 1.
2026-03-12 14:57:16 -06:00
SkyZeroZx 0837d25a70 refactor(common): Removes unused generic type parameters from KeyValueDiffers
Remove unused generic type parameters from KeyValueDiffers methods
2026-03-11 10:49:11 -07:00
Kristiyan Kostadinov f9ede9ec98 fix(core): ensure definitions compile
Includes the following changes to make sure the definitions for injectable compiler:
1. The types for the `factory` function now include the `parent` parameter.
2. `ɵɵFactoryDeclaration` is now defined as a function. We need this since the provider definition gets passed into the inejctable definition by reference.
3. `ɵɵdefineInjectable`, `ɵɵdefineNgModule` and `ɵɵdefinePipe` now return the typed definition, rather than `unknown`. This aligns with what we do for components and directives.
2026-03-10 09:58:18 -07:00
Miles Malerba b918beda32 feat(core): allow debouncing signals
Adds a utility `debounced` to create a debounced version of a signal,
represented as a `Resource`. The resource's value contained the
debounced value of the signal, while its status (`resolved`, `loading`,
or `error`) indicates if the value is settled, if there is a value
currently pending debounce, or if the source signal threw an error.
2026-03-09 13:21:52 -07:00
Matthieu Riegler 36936872c9 refactor(core): remove createNgModuleRef
`createNgModuleRef` was aliased to `createNgModule`

BREAKING CHANGE: `createNgModuleRef` was removed, use `createNgModule` instead
2026-03-05 12:02:27 -08:00
SkyZeroZx 17d3ea44e2 feat(core): add IdleRequestOptions support to IdleService
IdleService now accepts IdleRequestOptions,
enabling configuration of requestIdleCallback behavior in compatible environments.
2026-03-04 07:57:30 -08:00
Miles Malerba 2206efa55f feat(core): add special return statuses for resource params
Allows throwing from the resource's params function to transition the
resource to a status other than resolved.

In particular, the following values can be thrown from params:
- `ResourceParamsStatus.IDLE` causes the resource to become `idle`
  (equivalent to returning `undefined`)
- `ResourceParamsStatus.LOADING` causes the resource to become `loading`
- Any `Error` object causes the resource to become `error` and report
  the error that was thrown via `.error()`

To simplify chaining together resources, this PR also introduces a
context object passed into to the `params` functon. This context
contains a `chain` function that can be used to get the value of a
resource that the params want to depend on, while automatically
propagating the idle, loading, and erorr states of the resource forward.
2026-03-02 08:47:14 -08:00
Jessica Janiuk a5981b83a6 feat(core): support customization of @defer's on idle behavior
This commit makes the behavior of `on idle` in `@defer` configurable via DI.
It defines an `IdleService` interface that an application can implement and
provide to Angular:

```ts
@Injectable({providedIn: 'root'})
export class CustomIdleService implements IdleService {
  requestOnIdle(callback: () => void): number {...}
  cancelOnIdle(id: number): void {...}
}
```

Then the idle service can be used by providing the IDLE_SERVICE token with the custom implementation.
2026-02-24 17:19:09 -08:00
Enzo Cornand b9b5c279b4 refactor(core): enhance AnimationCallbackEvent.animationComplete signature
BREAKING CHANGE: change AnimationCallbackEvent.animationComplete signature

Fixes #65613
2026-02-20 10:04:00 -08:00
Ben Hong 13e019a1bb docs: add new debugging and troubleshooting di guide 2026-02-20 10:01:11 -08:00