mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
157 lines
5.1 KiB
Markdown
157 lines
5.1 KiB
Markdown
# Signal inputs
|
|
|
|
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.
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
Signal inputs are currently in [developer preview](/guide/releases#developer-preview).
|
|
|
|
</div>
|
|
|
|
|
|
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.
|
|
|
|
```typescript
|
|
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.
|
|
|
|
```typescript
|
|
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.
|
|
|
|
```html
|
|
<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](/guide/signals).
|
|
|
|
```typescript
|
|
export class InputSignal<T> extends Signal<T> { ... }`.
|
|
```
|
|
|
|
## Deriving values
|
|
|
|
As with signals, you can derive values from inputs using `computed`.
|
|
|
|
```typescript
|
|
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](/guide/signals#computed-signals).
|
|
|
|
## 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.
|
|
|
|
```typescript
|
|
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](https://en.wikipedia.org/wiki/Pure_function).
|
|
|
|
```typescript
|
|
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.
|
|
|
|
```html
|
|
<my-custom-comp disabled>
|
|
```
|
|
|
|
<div class="alert is-important">
|
|
|
|
Do not use transforms if they change the meaning of the input, or if they are [impure](https://en.wikipedia.org/wiki/Pure_function#Impure_functions).
|
|
|
|
Instead, use `computed` for transformations with different meaning, or an `effect` for impure code that should run whenever the input changes.
|
|
|
|
</div>
|
|
|
|
## 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:
|
|
|
|
1. Signal inputs are more **type safe**:
|
|
<br/>• Required inputs do not require initial values, or tricks to tell TypeScript that an input _always_ has a value.
|
|
<br/>• Transforms are automatically checked to match the accepted input values.
|
|
2. Signal inputs, when used in templates, will **automatically** mark `OnPush` components as dirty.
|
|
3. Values can be easily **derived** whenever an input changes using `computed`.
|
|
4. Easier and more local monitoring of inputs using `effect` instead of `ngOnChanges` or setters.
|