In this commit, we unsubscribe the `hasPendingTasks` subject to remove all active observers and enable granular garbage collection, as users may forget to unsubscribe manually when subscribing to `isStable`.
PR Close#59723
This commit adds a flag `forceSyncFirstEmit` which opts in to the pending
new behavior for `toObservable`, which emits the first value synchronously.
This flag is only really meant for use during a short migration period
while we update g3, and is not meant for prolonged usage. As a result, it's
marked deprecated.
PR Close#60640
Moves the `DOCUMENT` token from `common` into `core` since it's relevant for lots of SSR use cases and users shouldn't have to install `common` for it. The token is still exported through `common` for backwards compatibility.
PR Close#60663
This updates `createSignal` to use `signalGetFn` to define the signal getter and exports `signalGetFn` from the shared signal primitives.
PR Close#60497
This flag is effectively unused in Angular code that we've seen, and is only
serving to complicate the mental model of effects. It could be reintroduced
if needed.
PR Close#60535
When the HMR is enabled in Angular, all `@defer` block dependencies are loaded
eagerly, instead of waiting for configured trigger conditions. From the DX perspective,
it might be seen as an issue when all dependencies are being loaded eagerly. This commit
adds a logic to produce a message into the console to provide more info for developers.
PR Close#60533
This allows `ng.getDirectiveMetadata` to be implemented by Wiz and ACX with subtly different shapes to match the nuances of those frameworks.
Existing usage of `{Component,Directive}DebugMetadata` was moved over to `Angular{Component,Directive}DebugMetadata` as appropriate, since the implementation of `ng` in `@angular/core` is specific to Angular. Only the types support Wiz and ACX.
I opted to merge `ComponentDebugMetadata` and `DirectiveDebugMetadata` into a single type of all the frameworks including both components and directives (recall that components extend directives). The reasoning for this is because Wiz does not support directives (you can kind of think of "Wiz Directive" as an abstract class extended by "Wiz Components"). I felt that a `DirectiveDebugMetadata` containing only Angular and ACX types would be a bit of a trap and lead to bugs when used. It's safer to just have the single type containing all the possible results from `ng.getDirectiveMetadata`.
I also chose to leave the `ng` type as is internally, since `@angular/core` implements a specific concrete version of it narrowed to Angular types. Separately I defined an expanded `FrameworkAgnosticGlobalUtils` which redefines `ng.getDirectiveMetadata` to include Wiz and ACX. We want this type to exist in the Angular GitHub repo so it can be referenced as a common primitive across all three frameworks. This is sufficient for now, however longer term we will likely want to actually manually define the function types in this framework-agnostic interface and make Angular's version properly implement it rather than extend and overwrite Angular's type.
PR Close#60475
`TestBed.get` isn't type safe and has been deprecated for several years now. These changes remove it from the public API and a follow-up change will add an automated migration to `TestBed.inject`.
BREAKING CHANGE:
* `TestBed.get` has been removed. Use `TestBed.inject` instead.
PR Close#60414
Adds a hook in the same style as `postSignalSetFn` for running side effects when a producer has been created. This hook will be passed the reactive node being created.
PR Close#60333
This commit removes the previously added `rejectErrors` option from
`toSignal` which was meant to create similar behavior to what happens
with unhandled errors in `AsyncPipe`.
This option promotes unhandled exceptions and attaches behaviors that we
do not believe are desirable as an option offered by the framework:
* Unhandled errors that are thrown lose the context of where the error
ocurred. Throwing the error where the signal is read allows error
handling to be performed at the signal's usage location
* With this feature, the value of the signal remains set to the initial
value or the previous successful value coming out of the `Observable`.
We do not feel this is appropriate implicit behavior but should be an
explicit choice by the application. Signals are built to represent
state. When an observable stream is converted to a stateful
representation, there should be a choice made about what state should
be presented when an error occurs
* If an error occurs but the signal value is never read in its error
state, this is not an application state error that should result in an
unhandled exception.
* While Angular does not have error boundaries today, there is likely to
be investigation in the near future to address increased risk of
errors thrown from signals such as this in templates. Without
pre-designing any specifics, it is possible that this type of feature
would require the error to be thrown from the signal. We are subsequently
not prepared to commit to stabilizing the `toSignal` API with the
`rejectErrors` option and its current behavior.
Developers that desire similar behavior to `rejectErrors` have several
options, the simplest of which would be something similar to
`toSignal(myStream.pipe(catchError(() => EMPTY)))`.
PR Close#60397
Builds on the changes from #60137 to add support for two-way bindings on dynamically-created components. Example usage:
```typescript
import {createComponent, signal, twoWayBinding} from '@angular/core';
const value = signal('');
createComponent(MyCheckbox, {
bindings: [
twoWayBinding('value', value),
],
});
```
In the example above the value of `MyCheckbox` and the `value` signal will be kept in sync.
PR Close#60342
While still being supported because of ngUpgrade, string tokens are not recommended. Developers should use InjectionTokens or classes as tokens instead.
PR Close#60326
This change moves more logic to the primitives package by pushing
the equal configuration on a reactive node to the signal and
computed creation utilities.
PR Close#60300
Instead of relying on Microsoft's API extractor for `d.ts` bundling,
we are switching to Rollup-based `.d.ts` bundling.
This allows us to support code spliting, even for `.d.ts` files,
allowing for relative imports to be used between entry-points, without
ending up duplicating `.d.ts` definitions in two files. This would otherwise cause
problems with assignability of types.
It also nicely integrates into our existing rollup configuration, and
overall simplifies the `ng_package` rule even further!
Notably `tsup` also uses this rollup plugin, and it seems to work well.
Keep in mind that Microsoft's API extractor is pretty hard to integrate,
caused many problems in the past, and isn't capable of code splitting.
This aligns our d.ts bundling with the .mjs bundling (great alignment).
PR Close#60321
Removes the deprecated `InjectFlags` symbol from the `@angular/core` public API, as well as all the places that accept it. The previous commit includes an automated migration to switch over to the new way of passing in flags.
BREAKING CHANGE:
* `InjectFlags` has been removed.
* `inject` no longer accepts `InjectFlags`.
* `Injector.get` no longer accepts `InjectFlags`.
* `EnvironmentInjector.get` no longer accepts `InjectFlags`.
* `TestBed.get` no longer accepts `InjectFlags`.
* `TestBed.inject` no longer accepts `InjectFlags`.
PR Close#60318
This commit further restricts the deprecated type on injector.get to exclude
all but `string`. Progresses towards #48408
BREAKING CHANGE: The `any` overload has been removed from
`injector.get`. It now only supports `ProviderToken<T>` and (deprecated
since v4) `string`.
PR Close#60202
This should keep the existing behavior intact. Right now retrieve never returns back NOT_FOUND. This should not be the case, but tests fail if I do add this behavior so itll have to be later.
PR Close#60192
Note that this does NOT use the retrieve method yet. I believe we need to move the logic for notFoundValue into the inject implementation.
PR Close#60154
Reworks the `InputBinding` and `OutputBinding` functionality to be in object literals constructed in functions, rather than classes, because it seems like Terser was having a hard time tree shaking the classes when the functions weren't used.
PR Close#60137
Adds the new `outputBinding` function that allows users to listen to outputs on dynamically-created components in a similar way to templates. For example, here we create an instance of `MyCheckbox` and listen to its `onChange` event:
```ts
interface CheckboxChange {
value: string;
}
createComponent(MyCheckbox, {
bindings: [
outputBinding<CheckboxChange>('onChange', event => console.log(event.value))
],
});
```
Note that while it has always been possible to listen to events like this by getting a hold of of the instance and subscribing to it, there are a few key differences:
1. `outputBinding` behaves in the same way as if the event was bound in a template which comes with some behaviors like forwarding errors to the `ErrorHandler` and marking the view as dirty.
2. With `outputBinding` the listeners will be cleaned up automatically when the component is destroyed.
3. `outputBinding` accounts for host directive outputs by binding to them through the host. E.g. if the `onChange` event above was coming from a host directive, `outputBinding` would bind to it automatically.
Currently `outputBinding` is available only in `createComponent`, `ViewContainerRef.createComponent` and `ComponentFactory.create`, but it will serve as a base for APIs in the future.
PR Close#60137
Calling `setInput` while the component already has an `inputBinding` active can lead to inconsistent state. These changes add an error that will be thrown if that's the case.
PR Close#60137
Adds the ability to bind to inputs on dynamically-created components, either by targeting the component itself or one of its directives. The new API looks as follows:
```ts
const value = signal(123);
createComponent(MyComp, {
// Bind the value `'hello'` to `someInput` of `MyComp`.
bindings: [inputBinding('someInput', () => 'hello')],
directives: [{
type: MyDir,
// Bind the `value` signal to the `otherInput` of `MyDir`.
bindings: [inputBinding('otherInput', value)]
}]
});
```
This behavior overlaps with `ComponentRef.setInput`, with a few key differences:
1. `setInput` sets the value on *all* inputs whereas `inputBinding` only targets the specified directive and its host directives. This makes it easier to know which directive you're targeting.
2. `inputBinding` is executed as if it's in a template, making it consistent with how bindings behave for selector-matched components, whereas `setInput` executes outside the lifecycle of the component.
3. It resolves a long-standing issue with `setInput` where it wasn't possible to set the initial value of an input before the first change detection run.
Currently `inputBinding` is used only for `createComponent`, `ViewContainerRef.createComponent` and `ComponentFactory.create`, however it is going to be base for more APIs in the future.
PR Close#60137
Sets up the symbols used to power the upcoming `inputBinding` functionality.
I also fixed that `setDirectiveInput` was incorrectly only allowing strings for the `value` parameter.
PR Close#60137
Updates `createComponent`, `ViewContainerRef.createComponent` and `ComponentFactory.create` to allow the user to specify directives that should be applied when creating the component.
PR Close#60137
This commit ensures that rejections of the promise of the async function
passed to `PendingTasks.run` are not dangling and get reported to the
application error handler. This prevents what would likely be a common
dangling promise that could end up crashing the node process.
BREAKING CHANGE: `PendingTasks.run` no longer returns the result of the
async function. If this behavior is desired, it can be re-implemented
manually with the `PendingTasks.add`. Be aware, however, that promise rejections
will need to be handled or they can cause the node process to shut down
when using SSR.
PR Close#60044
This change casts the injector back and forth since all instances of
injector currently don't implement the `retrieve` method. Note that
the retrieve method is seen as optional, so that Angular can revert back to
inject if necessary.
PR Close#60090
Updates the signature of the `throwInvalidWriteToSignalError` to take the signal node in question and pass it along to the throwInvalidWriteToSignalErrorFn handler function. This allows the handler to e.g. include the signal name in error messaging.
PR Close#59600
The refactoring of `resource()` to use `linkedSignal()` introduced the
potential for a race condition where resources would get stuck and not update
in response to a request change. This occurred under a specific condition:
1. The request changes while the resource is still in loading state
2. The resource resolves the previous load before its `effect()` reacts to the
request change.
In practice, the window for this race is small, because the request change in
(1) will schedule the effect in (2) immediately. However, it's easier to
trigger this sequencing in tests, especially when one resource depends on the
output of another.
To fix the race condition, the resource impl is refactored to track the request
in its state, and ignore resolved values or streams for stale requests. This
refactoring actually makes the resource code simpler and easier to follow as
well.
Fixes#59842
PR Close#59851
`hasValue` attempts to narrow the type of a resource to exclude `undefined`.
Because of the way signal types merge in TS, this only works if the type
of the resource is the same general type as `hasValue` asserts.
For example, if `res` is `WritableResource<string|undefined>` then
`.hasValue()` correctly asserts that `res` is `WritableResource<string>` and
`.value()` will be narrowed. If `res` is `ResourceRef<string|undefined>`
then that narrowing does _not_ work correctly, since `.hasValue()` will
assert `res` is `WritableResource<string>` and TS will combine that for a
final type of `ResourceRef<string|undefined> & WritableResource<string>`.
The final type of `.value()` then will not narrow.
This commit fixes the above problem by adding a `.hasValue()` override to
`ResourceRef` which asserts the resource is of type `ResourceRef`.
Fixes#59707
PR Close#59708
Before `resource()` resolves, its value is in an unknown state. By default
it returns `undefined` in these scenarios, so the type of `.value()`
includes `undefined`.
This commit adds a `defaultValue` option to `resource()` and `rxResource()`
which overrides this default. When provided, an unresolved resource will
return this value instead of `undefined`, which simplifies the typing of
`.value()`.
PR Close#59655
This commit adds support for creating `resource()`s with streaming response
data. A streaming resource is defined by a `stream` option instead of a
`loader`, with `stream` being a function returning
`Promise<Signal<{value: T}|{error: unknown}>>`. Once the streaming loader
resolves to a `Signal`, it can continue to update that signal over time, and
the values (or errors) will be delivered to via the resource's state.
`rxResource()` is updated to leverage this new functionality to handle
multiple responses from the underlying Observable.
PR Close#59573
Originally the `T` in `Resource<T>` represented the resolved type of the
resource, and `undefined` was explicitly added to this type in the `.value`
signal. This turned out to be problematic, as it wasn't possible to write a
type for a resource which didn't return `undefined` values. Such a type is
useful for 2 reasons:
1. to support narrowing of the resource type when `Resource.hasValue()`
returns `true`.
2. for resources which use a different value instead of `undefined` to
represent not having a value (for example, array resources which want to
use `[]` as their default).
Instead, this commit changes `resource()` and `rxResource()` to return an
explicit `ResourceRef<T|undefined>`, and removes the union with `undefined`
from all types related to the resource's value. This way, it's trivially
possible to write `Resource<T>` to represent resources where `.value` only
returns `T`.
`hasValue()` then actually works to perform narrowing, by narrowing the
resource type to `Exclude<T, undefined>`.
PR Close#59024
This commit bumps up the stability status of the linkedSignal
to developer preview - clearly expressing our highier confidence
in this API.
PR Close#58684
This commit updates the code of the incremental hydration feature to make the `DeferBlockRegistry` class tree-shakable. The class is only needed for hydration cases and it should not be included into client bundles for client-only apps.
PR Close#58424
For scroll-blocking events like 'touchstart', 'touchmove', 'wheel' and 'mousewheel',
if passive option is not specified when adding the event listener, browser may give
a violation warning.
This PR allows us to set the passive option when calling event lib's addEvent().
PR Close#58316
This commit adds an operator to help rxjs observables important for rendering
keep the application unstable (and prevent serialization) until there is
an event (observable emits, completes, or errors, or the subscription is
unsubscribed). This helps with SSR for zoneless and also helps for when
operations are intentionally executed outside the Angular Zone but are
still important for SSR (i.e. angularfire and the zoneWrap helper hacks).
PR Close#56533