Signal inputs allow values to be bound from parent components.
Those values are exposed using a Signal
and can change during the lifecycle of your component.
HELPFUL: Signal inputs are currently in developer preview.
Angular supports two variants of inputs:
Optional inputs
Inputs are optional by default, unless you use input.required
.
You can specify an explicit initial value, or Angular will use undefined
implicitly.
Required inputs
Required inputs always have a value of the given input type.
They are declared using the input.required
function.
import {Component, input} from '@angular/core';@Component({...})export class MyComp { // optional firstName = input<string>(); // InputSignal<string|undefined> age = input(0); // InputSignal<number> // required lastName = input.required<string>(); // InputSignal<string>}
An input is automatically recognized by Angular whenever you use the input
or input.required
functions as initializer of class members.
Aliasing an input
Angular uses the class member name as the name of the input. You can alias inputs to change their public name to be different.
class StudentDirective { age = input(0, {alias: 'studentAge'});}
This allows users to bind to your input using [studentAge]
, while inside your component you can access the input values using this.age
.
Using in templates
Signal inputs are read-only signals.
As with signals declared via signal()
, you access the current value of the input by calling the input signal.
<p>First name: {{firstName()}}</p><p>Last name: {{lastName()}}</p>
This access to the value is captured in reactive contexts and can notify active consumers, like Angular itself, whenever the input value changes.
An input signal in practice is a trivial extension of signals that you know from the signals guide.
export class InputSignal<T> extends Signal<T> { ... }`.
Deriving values
As with signals, you can derive values from inputs using computed
.
import {Component, input, computed} from '@angular/core';@Component({...})export class MyComp { age = input(0); // age multiplied by two. ageMultiplied = computed(() => this.age() * 2);}
Computed signals memoize values. See more details in the dedicated section for computed.
Monitoring changes
With signal inputs, users can leverage the effect
function.
The function will execute whenever the input changes.
Consider the following example.
The new value is printed to the console whenever the firstName
input changes.
import {input, effect} from '@angular/core';class MyComp { firstName = input.required<string>(); constructor() { effect(() => { console.log(this.firstName()); }); }}
The console.log
function is invoked every time the firstName
input changes.
This will happen as soon as firstName
is available, and for subsequent changes during the lifetime of MyComp
.
Value transforms
You may want to coerce or parse input values without changing the meaning of the input. Transforms convert the raw value from parent templates to the expected input type. Transforms should be pure functions.
class MyComp { disabled = input(false, { transform: (value: boolean|string) => typeof value === 'string' ? value === '' : value, });}
In the example above, you are declaring an input named disabled
that is accepting values of type boolean
and string
.
This is captured by the explicit parameter type of value
in the transform
option.
These values are then parsed to a boolean
with the transform, resulting in booleans.
That way, you are only dealing with boolean
inside your component when calling this.disabled()
, while users of your component can pass an empty string as a shorthand to mark your component as disabled.
<my-custom-comp disabled>
IMPORTANT: Do not use transforms if they change the meaning of the input, or if they are impure.
Instead, use computed
for transformations with different meaning, or an effect
for impure code that should run whenever the input changes.
Why should we use signal inputs and not @Input()
?
Signal inputs are a reactive alternative to decorator-based @Input()
.
In comparison to decorator-based @Input
, signal inputs provide numerous benefits:
- Signal inputs are more type safe:
• Required inputs do not require initial values, or tricks to tell TypeScript that an input always has a value.
• Transforms are automatically checked to match the accepted input values. - Signal inputs, when used in templates, will automatically mark
OnPush
components as dirty. - Values can be easily derived whenever an input changes using
computed
. - Easier and more local monitoring of inputs using
effect
instead ofngOnChanges
or setters.