Commit Graph

122 Commits

Author SHA1 Message Date
Joey Perrott 31fdf0fbea refactor: migrate core to prettier formatting (#55488)
Migrate formatting to prettier for core from clang-format

PR Close #55488
2024-04-29 09:49:19 -07:00
Pawel Kozlowski 90389add7a fix(core): hide implementation details of ExperimentalPendingTasks (#55516)
The ExperimentalPendingTasks service was accidently exposing one of its
internal fields as a public one. This commit fixes this by marking the
field in question as private.

PR Close #55516
2024-04-25 08:51:01 -07:00
Pawel Kozlowski ac863ded48 feat(core): provide ExperimentalPendingTasks API (#55487)
The new ExperimentalPendingTasks API lets developers to add and remove
tasks that control applications stability: a pending task prevents
application from being stable.

This API is important for all the use-cases that depend on the concept
of stability and SSR serialization is a notable example.

Closes #53381

PR Close #55487
2024-04-24 11:23:10 -07:00
Gerald Monaco 5f06ca8f55 feat(core): add HOST_TAG_NAME token (#54751)
For ideal DOM usage, you would not unwrap an ElementRef outside of the browser. However, it's reasonable to want to find the tag name of the host node on the server, and so this introduces a HOST_TAG_NAME token that can be injected to read this value.

PR Close #54751
2024-04-17 15:50:31 -07:00
Andrew Scott f09c5a7bc4 feat(core): Add zoneless change detection provider as experimental (#55329)
This commit adds the zoneless change detection provider function to the
public API surface as experimental.

PR Close #55329
2024-04-16 20:51:25 +02:00
Matthieu Riegler e606ac6023 refactor(core): transform Predicate from interface to type (#54566)
This interface should have been a type as there are no other properties

PR Close #54566
2024-04-16 17:26:53 +02:00
Pawel Kozlowski cfed97d2a9 docs: update public APIs golden after doc changes (#55346)
Build got broken after merging https://github.com/angular/angular/pull/54577
due to the missing golden files update for the public API.

PR Close #55346
2024-04-15 14:19:54 +02:00
Andrew Scott 6534c035c0 fix(core): Remove deprecated Testability methods (#53768)
This commit removes the long-deprecated Testability methods that track
pending tasks. This is done by NgZone today and will be done by other
APIs in zoneless.

BREAKING CHANGE: Testability methods `increasePendingRequestCount`,
`decreasePendingRequestCount` and `getPendingRequestCount` have been
removed. This information is tracked with zones.

PR Close #53768
2024-04-12 14:49:23 -07:00
Andrew Scott fdd560ea14 feat(core): Add ability to configure zone change detection to use zoneless scheduler (#55252)
This commit adds a configuration option to zone-based change detection
which allows applications to enable/disable the zoneless scheduler.
When the zoneless scheduler is enabled in zone-based applications,
updates that happen outside the Angular zone will still result in a
change detection being scheduled. Previously, Angular change detection
was solely based on the state of the Angular Zone.

PR Close #55252
2024-04-12 12:29:05 -07:00
Paul Gschwendtner 72adf0dac7 refactor(core): improve API documentation for input after angular.dev support (#54925)
This commit improves the API documentation for `input` after
we added support for initializer APIs in angular.dev docs generation.

Changes:

- Rename `ReadT` to `T`. This conceptually makes it easy to talk about
  inputs of type `T` if there is no transform involved. The common case.
- Rename `WriteT` to `TransformT`. This makes it clear that this is the
  type that the "transform" needs to handle.
- Improves the "overall" description of the input function so that it
  can be shown as a general overview for the API site.
- Improves usage notes to be a little more helpful, yielding more useful
  content in the API docs usage notes section.
- Add short JSDoc description for each individual overload.

PR Close #54925
2024-03-26 09:17:20 -07:00
Paul Gschwendtner 866271a1c6 refactor(core): EventEmitter implements OutputRef. (#54650)
An `EventEmitter` is a construct owned by Angular that should be
used for outputs as of right now.

As we are introducing the new `OutputRef` interface for the new output
function APIs, we also think `EventEmitter` should implement
`OutputRef`— ensuring all "known" outputs follow the same contract.

This commit ensures `EventEmitter` implements an `OutputRef`

Note: An output ref captures the destroy ref from the current injection
context for clean-up purposes. This is also done for `EventEmitter` in a
backwards compatible way:

- not requiring an injection context. EventEmitter may be used
  elsewhere.
- not cleaning up subscriptions/completing the emitter when the
  directive/component is destroyed. This would be a change in behavior.

Note 2: The dependency on `DestroyRef` causes it to be retained in all
bundling examples because ironically `NgZone` uses `EventEmitter`- not
for outputs. The code is pretty minimal though, so that should be
acceptable.

`EventEmitter` will now always retain `NgZone. This increases the
payload size slightly around 800b for AIO. Note that the other increases
were coming from previous changes. This commit just pushed it over the
threshold.

PR Close #54650
2024-03-06 12:34:39 +01:00
Paul Gschwendtner 30355f6719 refactor(core): model() implements OutputRef (#54650)
A model signal is technically an output, at runtime and conceptually.

This commit re-uses the shared output ref logic and ensures the
interfaces match.

PR Close #54650
2024-03-06 12:34:38 +01:00
Paul Gschwendtner c687b8f453 feat(core): expose new output() API (#54650)
This commit exposes the new `output()` API with numerous benefits:

- Symmetrical API to `input()`, `model()` etc.
- Fixed types for `EventEmitter.emit`— current `emit` method of
  `EventEmitter` is broken and accepts `undefined` via `emit(value?: T)`
- Removal of RxJS specific concepts from outputs. error channels,
  completion channels etc. We now have a simple consistent
  interface.
- Automatic clean-up of subscribers upon directive/component destory-
  when subscribed programmatically.

```ts
@Directive({..})
export class MyDir {
  nameChange = output<string>();     // OutputEmitterRef<string>
  onClick = output();                // OutputEmitterRef<void>
}
```

Note: RxJS custom observable cases will be handled in future commits via
explicit helpers from the interop.

PR Close #54650
2024-03-06 12:34:38 +01:00
Kristiyan Kostadinov 331b16efd2 feat(core): add API to inject attributes on the host node (#54604)
Angular has the `@Attribute` decorator that allows for attributes to be injected from the host node, but we don't have an equivalent for the `inject` function. These changes introduce the new `HostAttributeToken` class that can be used to inject attributes similarly to `@Attribute`. It can be used as follows:

```typescript
import {HostAttributeToken, inject} from '@angular/core';

class MyDir {
  someAttr = inject(new HostAttributeToken('some-attr'));
}
```

The new API works similarly to `@Attribute` with one key exception: it will throw a DI error when the attribute doesn't exist, instead of returning `null` like `@Attribute`. We made this change to align its behavior closer to other injection tokens.

PR Close #54604
2024-02-27 15:18:41 -08:00
Kristiyan Kostadinov 58666e905d refactor(core): reuse input signal node for models (#54387)
Reworks the model so that it reuses `INPUT_SIGNAL_NODE` instead of implementing its own.

PR Close #54387
2024-02-12 11:01:52 -08:00
Kristiyan Kostadinov 4a7ca50328 refactor(core): avoid wrapper around subscribe return value (#54387)
Reworks `ModelSignal.subscribe` so it doesn't have to wrap its value to look like a subscription.

PR Close #54387
2024-02-12 11:01:52 -08:00
Kristiyan Kostadinov dab5fc30ee fix(core): expose model signal subcribe for type checking purposes (#54357)
The `@internal` in the comment above `ModelSignal.subscribe` ended up marking the method as internal even though it wasn't meant to be.

PR Close #54357
2024-02-09 09:58:55 +00:00
Kristiyan Kostadinov e921e108e1 refactor(core): correctly distinguish getter functions from writable signals (#54252)
Fixes that `ɵunwrapWritableSignal` inferring getter functions as not matching the interface of `WritableSignal` instead of preserving them.

PR Close #54252
2024-02-07 16:36:15 +00:00
Kristiyan Kostadinov 702ab28b4c feat(core): add support for model inputs (#54252)
Adds support for model inputs in the framework. `model()` returns a writable signal that implicitly defines a input/output pair that can be used either in two-way bindings to keep two values in sync or by binding individually to the input and output. When the value of the `model` changes, it will emit an event with the current value.

Furthermore, these changes expand two-way bindings to accept `WritableSignal`. This will make it easier to transition existing code to signals in a backwards-compatible way.

Example:

```ts
@Directive({
  selector: 'counter',
  standalone: true,
  host: {
    '(click)': 'increment()',
  }
})
export class Counter {
  value = model(0);

  increment(): void {
    this.value.update(current => current + 1);
  }
}

@Component({
  template: `<counter [(value)]="count"/> The current count is: {{count()}}`,
})
class App {
  count = signal(0);
}
```

PR Close #54252
2024-02-07 16:36:09 +00:00
Paul Gschwendtner c023e8d58f refactor(core): improve IDE completion of read option for signal queries (#54280)
This commit improves IDE completion of the `read` option for
signal-based queries.

Currently, TS only matches the first overload when starting out with
defining a query. TS doesn't build up the combination of possible
options from the second overload- so in practice users will only see
IDE completions for the `descendants` option.

This is not a problem for view queries as the only option is `read`, so
TS will always match the overload with the `read` option.

```
class X {
  query = contentChild('', {^^ <--
    here we should completion for `read` an `descendants`
}
```

PR Close #54280
2024-02-07 16:35:14 +00:00
Pawel Kozlowski e95ef2cbc6 feat(core): expose queries as signals (#54283)
This commit exposes authoring functions for queries as signals
thus making those generally available.

PR Close #54283
2024-02-06 19:31:58 +00:00
Paul Gschwendtner b78042f3a5 refactor(core): separate InputSignal and InputSignalWithTransform (#54053)
This commit separates `InputSignal` for input signals with transforms.
The reason being that most of the time, signal inputs are not using
transforms and the generics are rather confusing.

Especially for users with inferred types displayed in their IDEs, the
input signal types are seemingly complex, even if no transform is used.

For this reason, we are introducing a new type called
`InputSignalWithTransform`. This type will be used for inputs with
transforms, while non-transform inputs just use `InputSignal`.

A notable fact is that `InputSignal` extends `InputSignalWithTransform`,
with the "identity transform". i.e. there is no transform. This allows
us to share the code for input signals. In practice, we don't expect
users to pass around `InputSignal`'s anyway.

PR Close #54053
2024-01-26 19:10:56 +00:00
Dylan Hunn d0ce0110e8 Revert "refactor(core): improve forwardRef typings (#53880)" (#53961)
This reverts commit af6f6e6448.

PR Close #53961
2024-01-17 13:56:07 -08:00
Pawel Kozlowski af6f6e6448 refactor(core): improve forwardRef typings (#53880)
This commit improves the forwardRef typings for better
type safety and inference.

PR Close #53880
2024-01-12 10:26:01 -08:00
Paul Gschwendtner 863be4b698 feat(core): expose new input API for signal-based inputs (#53872)
Enables signal inputs for existing Zone based components.
This is a next step we are taking to bring signal inputs earlier to the Angular community.

The goal is to enable early access for the ecosystem to signal inputs, while we are continuing
development of full signal components as outlined in the RFC. This will allow the ecosystem
to start integrating signals more deeply, prepare for future migrations, and improves code quality
and DX for existing components (especially for OnPush).

Based on our work on full signal components, we've gathered more information and learned
new things. We've improved the API by introducing a way to intuitively declare required inputs,
as well as improved the API around initial values. We even support non-primitive initial values
as the first argument to the `input` function now.

```ts
@Directive({..})
export class MyDir {
  firstName = input<string>();            // string|undefined
  lastName = input.required<string>();    // string
  age = input(0);                         // number
```

PR Close #53872
2024-01-10 12:33:31 -08:00
Paul Gschwendtner 7fb4a37f7d refactor(core): introduce runtime InputSignal implementation (#53571)
This commit introduces the runtime `InputSignal` implementation.
Input initializers using `input` or `input.required` will result in
an instance of `InputSignal` to be created.

An input signal extends the signal primtive, with a couple of small
differences:

 - it's a readonly signal. There is no public `set` or `update`.
 - equality is non-configurable. As per CD semantics, the value is
   guaranteed to be different when the `property` instruction attempts
   to update an input signal.
 - we support a `transform` function, that allows transforming input
   values. The transform is called whenever the input is set. An
   alternative could have been to follow computed-semantics and call the
   transform upon accessing, if dirty.

In the future, we might change this to extend the computed reactive
node, so that we can support computed inputs that do not rely on
continious bound value assignments. See signal based components RFC.

PR Close #53571
2024-01-04 12:07:13 -08:00
Paul Gschwendtner bbd918acd3 refactor(core): introduce signal input() function and compiler detection (#53521)
This commit introduces a function for declaring inputs in
components. The function is called `input`. It comes in two flavors:

- `input` for optional inputs with initial values
- `input.required` for required inputs

Inputs are declared as class members, like with `@Input`- except that
the class field will no longer hold the input value directly. Angular
takes control over the input field and exposes the input value as a
signal. The runtime implementation will follow in future commits.

This commit simply introduces:

- initial compiler detection to recognize such inputs in classes
- the initial signature of `input` and `input.required`.

Note: the defer size test is flawed and there is no minification- hence
this commit also needs to incorporate the new dependency graph changes.

PR Close #53521
2023-12-13 15:44:00 -08:00
Alex Rickabaugh 1f528f1e8d refactor(core): mark effect as developer preview again (#52490)
Re-add the `@developerPreview` flags to `effect()`. While we don't expect
the `effect` API itself to change, we may change how other FW APIs interact
with `effect`s. Also, add a missing export for one of those effect APIs.

PR Close #52490
2023-11-02 15:29:44 -07:00
Andrew Scott 75725fb69f docs(core): Deprecate ChangeDetectorRef.checkNoChanges (#52431)
The `checkNoChanges` method does not belong in the API of production interface. `checkNoChanges` is
limited to testing and should not be used in any application code. Test
code should use `ComponentFixture` instead of `ChangeDetectorRef`.
Additionally, it is not desirable to have the `checkNoChanges` API
available in a context where `detectChanges` is not run first.

DEPRECATED: `ChangeDetectorRef.checkNoChanges` is deprecated.

Test code should use `ComponentFixture` instead of `ChangeDetectorRef`.
Application code should not call `ChangeDetectorRef.checkNoChanges` directly.

PR Close #52431
2023-10-31 13:38:44 -07:00
Matthieu Riegler a0dc12bfe8 refactor(core): deprecate the NgProbeToken (#51396)
DEPRECATED: NgProbeToken

The `NgProbeToken` is not used internally since the transition from View Engine to Ivy. The token has no utility and can be removed from applications and libraries.

PR Close #51396
2023-10-13 12:19:05 +02:00
Matthieu Riegler f0da7c2e44 feat(migrations): schematic to remove deprecated CompilerOptions properties (#49672)
`useJit` and `missingTranslation` have been deprecated since v13 and  are unused in Ivy. They can be safely removed.

PR Close #49672
2023-10-10 09:35:55 -07:00
Pawel Kozlowski 00128e3853 fix(core): drop mutate function from the signals public API (#51821) (#51986)
This change removes the `mutate` method from the `WritableSignal` interface and
completely drops it from the public API surface.

The initial API proposal for Angular signals included the mutate method, allowing
in-place modification of JS objects, without changing their references (identity).
This was based on the reasoning that identity change on modification is not necessary
as we can send the “modified” notification through the signals graph.
Unfortunately the signal-specific change notification is lost as soon as we read
signal value outside of a reactive context (outside of a reactive graph).
In other words - any code outside of the Angular signals library can’t know
that an object is modified.

Secondly, to make the mutate method work, we’ve defaulted the signal value equality function
to the one that considers non-primitive values as always different.
This is unfortunate for people working with immutable data structures
(this is notably the case for the popular state management libraries)
as the default equality function de-optimizes memoization in computed,
making the application less performant.

Given the above reasons we prefer to remove the mutate method in the signals library -
at least for now. There are just too many sharp edges and tradeoffs that we don’t fully
understand yet.

BREAKING CHANGE:

The  `mutate` method was removed from the `WritableSignal` interface and completely
dropped from the public API surface. As an alternative please use the update method and
make immutable changes to the object.

Example before:

```typescript
items.mutate(itemsArray => itemsArray.push(newItem));
```

Example after:

```typescript
items.update(itemsArray => [itemsArray, …newItem]);
```

PR Close #51986
2023-10-06 15:12:00 -07:00
Alex Rickabaugh 8f5cbcc845 refactor: move signals code into primitives package (#51986)
This commit reorganizes the Angular code a bit, and moves signals into a
newly defined `@angular/core/primitives` location. This will be used inside
g3 to allow non-Angular targets to depend on the signals core without
incurring a dependency on the whole framework.

PR Close #51986
2023-10-06 15:12:00 -07:00
Andrew Scott b6b9eae7e7 Revert "fix(core): drop mutate function from the signals public API (#51821)" (#52081)
This reverts commit c7ff9dff2c.
requires cleanup of 2 uses internally first

PR Close #52081
2023-10-06 10:31:48 -07:00
Pawel Kozlowski c7ff9dff2c fix(core): drop mutate function from the signals public API (#51821)
This change removes the `mutate` method from the `WritableSignal` interface and
completely drops it from the public API surface.

The initial API proposal for Angular signals included the mutate method, allowing
in-place modification of JS objects, without changing their references (identity).
This was based on the reasoning that identity change on modification is not necessary
as we can send the “modified” notification through the signals graph.
Unfortunately the signal-specific change notification is lost as soon as we read
signal value outside of a reactive context (outside of a reactive graph).
In other words - any code outside of the Angular signals library can’t know
that an object is modified.

Secondly, to make the mutate method work, we’ve defaulted the signal value equality function
to the one that considers non-primitive values as always different.
This is unfortunate for people working with immutable data structures
(this is notably the case for the popular state management libraries)
as the default equality function de-optimizes memoization in computed,
making the application less performant.

Given the above reasons we prefer to remove the mutate method in the signals library -
at least for now. There are just too many sharp edges and tradeoffs that we don’t fully
understand yet.

BREAKING CHANGE:

The  `mutate` method was removed from the `WritableSignal` interface and completely
dropped from the public API surface. As an alternative please use the update method and
make immutable changes to the object.

Example before:

```typescript
items.mutate(itemsArray => itemsArray.push(newItem));
```

Example after:

```typescript
items.update(itemsArray => [itemsArray, …newItem]);
```

PR Close #51821
2023-10-05 14:40:50 -07:00
Paul Gschwendtner 4427e1ebc2 feat(core): create function to assert not running inside reactive context (#52049)
Some functions or code should never run inside reactive contexts. A
function to assert that will help putting guard rails in place.

PR Close #52049
2023-10-05 11:08:05 -07:00
Gerald Monaco 545db6d22d refactor(core): support phases in afterRender and afterNextRender (#51559)
Support for scheduling after*Render callbacks into various phases to minimize reflows

PR Close #51559
2023-09-18 10:40:18 +02:00
Kristiyan Kostadinov 59387ee476 feat(core): support styles and styleUrl as strings (#51715)
Adds support for passing in `@Component.styles` as a string. Also introduces a new `styleUrl` property on `@Component` for providing a single stylesheet. This is more convenient for the most common case where a component only has one stylesheet associated with it.

PR Close #51715
2023-09-12 13:57:07 -07:00
Jeremy Mowery 635318fd61 refactor: add readonly to public InjectionToken types (#51407)
This fixes warnings caused by an internal lint rule

refactor: add readonly to public InjectionToken types

PR Close #51407
2023-09-12 12:55:14 -07:00
Jeremy Mowery be3edad60e refactor: add readonly to public InjectionToken types (#51125)
We enabled a lint rule internally to require that multi-provided
`InjectionToken`s have a `readonly` array type, the tokens in this
PR do not follow this rule and are causing lint violations.

Fixes #51124

PR Close #51125
2023-08-14 17:17:35 -07:00
Matthieu Riegler 56566fe3ed refactor(core): deprecate PACKAGE_ROOT_URL token (#51222)
Usage was removed in #43884

PR Close #51222
2023-08-07 09:21:45 -07:00
Gerald Monaco e53d4ecf4c feat(core): add afterRender and afterNextRender (#50607)
Add and expose the after*Render functions as developer preview

PR Close #50607
2023-08-01 13:02:27 -07:00
Andrew Kushnir cdaa2a8a9e feat(core): support Provider type in Injector.create (#49587)
This commit updates the Injector.create function to accept the `Provider` type in addition to the `StaticProvider` type. This should make it easier to work with the Injector.create function and have less type casts if you have a list of `Provider`s available.

PR Close #49587
2023-07-28 14:38:05 -07:00
Antonio Pekeljevic 1ec2aa902d docs: add missing jsdocs for static ngzone methods (#50924)
PR Close #50924
2023-07-11 08:28:38 -07:00
Kristiyan Kostadinov 29340a0678 fix(core): expose input transform function on ComponentFactory and ComponentMirror (#50713)
Exposes the function used to transform an input on `ComponentFactory.inputs` and `ComponentMirror.inputs`. We'll need this to support input transforms in `elements`.

PR Close #50713
2023-06-22 09:47:15 -07:00
Kristiyan Kostadinov 68017d4e75 feat(core): add ability to transform input values (#50420)
According to the HTML specification most attributes are defined as strings, however some can be interpreted as different types like booleans or numbers. [In the HTML standard](https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#boolean-attributes), boolean attributes are considered `true` if they are present on a DOM node and `false` if they are omitted. Common examples of boolean attributes are `disabled` on interactive elements like `<button>` or `checked` on `<input type="checkbox">`. Another example of an attribute that is defined as a string, but interpreted as a different type is the `value` attribute of `<input type="number">` which logs a warning and ignores the value if it can't be parsed as a number.

Historically, authoring Angular inputs that match the native behavior in a type-safe way has been difficult for developers, because Angular interprets all static attributes as strings. While some recent TypeScript versions made this easier by allowing setters and getters to have different types, supporting this pattern still requires a lot of boilerplate and additional properties to be declared. For example, currently developers have to write something like this to have a `disabled` input that behaves like the native one:

```typescript
import {Directive, Input} from '@angular/core';

@Directive({selector: 'mat-checkbox'})
export class MatCheckbox {
  @Input()
  get disabled() {
    return this._disabled;
  }
  set disabled(value: any) {
    this._disabled = typeof value === 'boolean' ? value : (value != null && value !== 'false');
  }
  private _disabled = false;
}
```

This feature aims to address the issue by introducing a `transform` property on inputs. If an input has a `transform` function, any values set through the template will be passed through the function before being assigned to the directive instance. The example from above can be rewritten to the following:

```typescript
import {Directive, Input, booleanAttribute} from '@angular/core';

@Directive({selector: 'mat-checkbox'})
export class MatCheckbox {
  @Input({transform: booleanAttribute}) disabled: boolean = false;
}
```

These changes also add the `booleanAttribute` and `numberAttribute` utilities to `@angular/core` since they're common enough to be useful for most projects.

Fixes #8968.
Fixes #14761.

PR Close #50420
2023-05-30 13:01:13 -07:00
markostanimirovic 165b8b647c fix(core): allow passing value of any type to isSignal function (#50035)
Unlike the current signature where the input argument must a function, this change allows an input of any type to be passed to the `isSignal` function.

PR Close #50035
2023-05-16 09:22:05 -07:00
Matthieu Riegler bb6a3e849e refactor(core): throw an error when APP_INITIALIZER token is not an array. (#49860)
Providing a non-multi token for `APP_INITIALIZER` now throws `INVALID_MULTI_PROVIDER` (NG209)

PR Close #49860
2023-04-23 18:31:24 -07:00
Jessica Janiuk 2845017f83 Revert "refactor(core): throw an error when APP_INITIALIZER token is not an array. (#49860)" (#49893)
This reverts commit bf2e11c035.

PR Close #49893
2023-04-17 18:57:47 +00:00
Matthieu Riegler bf2e11c035 refactor(core): throw an error when APP_INITIALIZER token is not an array. (#49860)
Providing a non-multi token for `APP_INITIALIZER` now throws `INVALID_MULTI_PROVIDER` (NG209)

PR Close #49860
2023-04-17 13:37:09 +00:00