Episode 23/50: Zoneless without Signals, Roadmap, Signal Inputs

ng-news - Dec 22 '23 - - Dev Community

Zoneless applications might be possible even without the migration to Signals. Mid-January we can expect Angular 17.1 with Signal Inputs.

Project Plan for Reactivity/Signals

The Angular team published the project plan for the Signals/Reactivity roadmap, where we can see what tasks they are currently working on and more.

https://github.com/orgs/angular/projects/31

Zoneless without Signals

The roadmap unveiled a huge surprise: Getting zoneless applications without migrating to Signals will be possible.

This is especially good news for existing applications requiring years to migrate to Signals.

A future zoneless application must work with ChangeDetectionStrategy set to OnPush. Until now, zone.js triggered the change detection upon DOM Events or asynchronous tasks. Without zone.js, which is zoneless, the markForCheck methods will trigger the Change Detection directly.

markForCheck is already automatically executed by handled DOM Events, the async pipe, and immutable changes in property binding. In all other cases, like asynchronous tasks, we must run markForCheck manually via the ChangeDetectorRef.

The alternative is to go directly with Signals.

Again, zoneless with OnPush requires a new scheduler, which is not available yet.

Signal Inputs

We can expect Angular 17.1 in mid-January. It will deliver Signal Inputs. They will replace the current @Input decorator with a simple function called input(). The resulting type is a Signal, which we can easily use in a computed or effect.

The input function expects a generic type or a default value. If the default value is unavailable, the resulting type will be a union type of undefined and the actual type. There is also a required, which removes the undefined type but would throw an error during runtime if the value is missing.

Signal Inputs will streamline the code. Instead of using ngOnChanges, a computed or effect is enough.

#1 Initial PR for signal inputs #53521

See individual commits.


Implements 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.

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

Technical notes Be aware that signal inputs in Zone components do not necessarily follow all the semantics as expected in the RFC. Signal inputs in Zone components are not treated as "computeds". This means, signal inputs are only updated when change detection runs. Not to be confused with the semantics for full signal components in the RFC.

Components can have inputs defined with the @Input decorator and input() function for signal inputs. The aim is to ease migration/adoption of signal inputs. Full signal components are not expected to support this. For example:

// Both of these are valid in the same component
age = input();
@Input() name = '';
Enter fullscreen mode Exit fullscreen mode

As stated above, we have slightly changed the API signature for inputs based on our learnings with the RFC-proposed API. We were facing a technical limitation that made it impractical to support the API where the first argument of input could take either options or an initial value. This was mostly related to complexity around static analysis and enabling future single file compilations. Other than that, the changes also allowed us to unlock a few more things as mentioned above.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .