Signal Input is now available in developer preview for Angular devs

Paul Gschwendtner
Angular Blog
Published in
5 min readFeb 22, 2024

--

In Angular 17.1 we introduced signal-based inputs as a reactive alternative to decorator-based @Input().

The new inputs provide developers with new ways that:

  • allow you to integrate and benefit from Angular signals today:
    ▹ providing easier ways to run logic whenever an input changes.
    efficient solutions for deriving state from inputs.
    ▹ enabling a smoother experience with OnPush and future Zoneless.
  • improve code quality and developer productivity by increasing type safety of inputs.

Those are available in developer preview and we would like your feedback!

What are signal inputs?

As with @Input, signal inputs allow values to be bound from parent components. A key difference with signal inputs is that these values are exposed using a Signal and can change during the lifecycle of your component.

Now, developers can leverage the power of signals to respond effectively to these potential changes in a reactive way. Angular supports two variants of signal inputs.

  • Optional inputs — Inputs are optional by default. You can specify an explicit initial value, or Angular will use undefined implicitly as the initial value.
  • Required inputs — Required inputs always have a value of the given input type. There can be no initial value, and required inputs are declared using the input.required function.

An input is automatically recognized by Angular whenever you use the input or input.required functions as initializer of class members. The following demonstrates how you can declare signal inputs in your application:

import {Component, input} from '@angular/core';

@Component({…})
export class MyComp {
// optional inputs
firstName = input<string>();
age = input(0);

// required inputs
lastName = input.required<string>();
}

After they are defined, you can use them in your templates with the same syntax as other signals:

<p>First name: {{firstName()}}</p>
<p>Last name: {{lastName()}}</p>

Find out more in the dedicated guide for signal inputs. https://angular.io/guide/signal-inputs.

Why Signal inputs are a better fit for your application?

In comparison to decorator-based @Input, signal inputs provide numerous benefits:

  • Signal inputs, when used in templates, will automatically mark OnPush components as dirty.
    ▹ This improves code quality and developer experience (DX), and is paving the way for Zoneless
  • Signal inputs are more type safe:
    ▹ Unlike today, required inputs do not require initial values, or other tricks to satisfy TypeScript.
    ▹ Transforms are type-checked to match the accepted input values.
  • Values can be easily derived whenever an input changes using a computed, like with other signals.
  • Easier and more local monitoring of inputs using effect instead of ngOnChanges or setters.

The Angular team recommendation is to use signal inputs once they are out of developer preview and promoted to production ready in an upcoming version.

Taking advantage of the power of Signals

Signals provide a powerful reactivity model that enables you to efficiently monitor changes, derive values, while automatically notifying Angular whenever specific parts of your application need to be re-rendered. This makes it easier and safer to build performant applications that only refresh the parts that actually changed.

Below we are highlighting some potential use-cases.

Declaration and rendering

This example demonstrates how you can declare a signal input for a component and display its value.

import {input} from '@angular/core';

@Component({
// …
template: `Your name is: {{yourName()}}`,
})
class HelloComponent {
yourName = input.required<string>();
}

Watching changes

This example watches changes to a firstName input and uses effect() to react to those changes:

import {input, effect} from '@angular/core';

class MyComp {
firstName = input.required<string>();

constructor() {
effect(() => {
// will be called when `firstName` is initialized or changes.
console.log(this.firstName());
});
}
}

Deriving values

You can efficiently derive values based on signal inputs by using computed. Signal inputs can be used in a computed like any other signal in your application.

In the following example, we derive a value from an input called age. Whenever age changes, the ageMultiplied field will be notified and can re-run to multiply the age by two. On the other hand, if age does not change, the ageMultiplied derivation will efficiently use the previous memoized value without executing.

import {Component, input, computed} from '@angular/core';

@Component({…})
export class MyComp {
age = input(0);

// age multiplied by two.
ageMultiplied = computed(() => this.age() * 2);
}

Value Transforms

Signal inputs support the same features as decorator-based inputs. You can specify a transform function for a signal input to parse raw values to your expected input type.

Note that value transforms should never change the meaning of an input. More information on this in the new guide on angular.dev — https://angular.io/guide/signal-inputs#value-transforms

export class MyCheckboxComponent {
disabled = input(false, {
// supports `<my-checkbox disabled="" />` as a shorthand
transform: (v: boolean|string) => typeof v === 'string' ? v === '' : v,
});
}

Aliasing

You can also do things, like aliasing an input to meet your needs:

export class StudentDirective {
age = input(0, {alias: 'studentAge'});
}

Only the beginning

We’re overjoyed to bring this feature to the Angular community in developer preview. Signal inputs can be used today, and are production ready. Developer preview allows us to make changes in response to feedback that we receive from the community.

With that in mind, we’d love your feedback as we continue to stabilize signal inputs. There were a few complicated trade-offs and other questions for upcoming APIs:

  • The shorthand for input<string>() may be confusing as the input implicitly uses undefined as initial value.
    — Is this confusing because the generic just shows string?
    — We believe the shorthand is useful as we saw the majority of inputs using undefined as initial value inside the Google codebase.
  • Inputs are now read-only.
    — Previously with @Input, you were able to desynchronize the input by updating from within the component.
    — Is this affecting your application? If you intend to update the input, please consider using model() and exposing the updated state to your component to consumers. Why does this not work for you?

Your feedback is valuable and we look forward to hearing from you. If you have feedback, consider letting us know in the comments, on GitHub or X.

Be sure to try out signal inputs today by installing the latest version of Angular with ng update.

Thanks and keep us updated!

--

--