Streamlining Communication: New Signals API in Angular 17.3
Tags: angular, signals, components, webdev
Published: 2024-03-25 09:00:00

## Introduction

Angular 17.3 introduces a developer preview of a new Signals API, a feature unveiled at the [ngConf 2024 keynote](https://www.youtube.com/watch?v=nIBseTi6RVk) by [Jeremy Elbourn](https://hachyderm.io/@jelbourn) and [Minko Gechev](https://twitter.com/mgechev).

This API promises to simplify component communication and data management in your Angular applications. This article explores the four key features of this API -- Signal Queries, Signal Inputs, Signal Outputs (with a twist), and Model Inputs -- highlighting the potential benefits they bring.

### 1. Effortless Reference Retrieval with Signal Queries
Traditionally, Angular components have relied on decorators like `@ViewChild` and `@ContentChildren` to access template references. While functional, these decorators can add some verbosity to your code.

The Signals API offers a cleaner alternative. It allows you to directly declare references as signals within your component class. This not only improves readability but also introduces a new feature - the ability to mark a signal as required using `.required`. With this addition, Angular will throw an error if the query result is missing, helping you catch potential issues early in development.

Here's a before-and-after example to illustrate the change:

```ts
// Before (using decorators)
@Component({/* ... */})
export class Menu {
  @ViewChild('trigger') trigger: ElementRef;
  @ContentChildren(MenuItem) 
  items: QueryList<MenuItem> | undefined;
}

// After (using signals)
@Component({/* ... */})
export class Menu {
  trigger = viewChild('trigger');
  // New: mark as required
  items = contentChildren(MenuItem).required;
}
```

### 2. Signal Inputs: Powering Computed Properties and Effects
The `@Input` decorator has been a cornerstone for passing data into components. However, it can feel limiting when working with computed properties or effects within your component.

The Signals API introduces signal-based inputs that seamlessly integrate with these functionalities. These signal inputs can be used within computed expressions and effects, providing a more reactive approach to data handling.

Here's an example showcasing the difference:

```ts
// Before (using @Input)
@Component({/* ... */})
export class Checkbox {
  @Input() disabled = false;
  @Input({required: true}) checked!: boolean;
}

// After (using signal inputs)
@Component({/* ... */})
export class Checkbox {
  disabled = input(false);
  checked = input.required<boolean>();
}
```

### 3. Outputs: Maintaining Consistency with Signal-Based Style
While the Signals API introduces a new approach for inputs, outputs still leverage the familiar `@Output` decorator for consistency. That means they are not signal-based. This ensures a clear distinction between receiving data (inputs) and emitting events (outputs).

Here's a comparison highlighting the separation:

```ts
// Before (mixed styles)
@Component({/* ... */})
export class Checkbox {
  disabled = input(false);
  @Output() toggled = new EventEmitter<boolean>();
}

// After (consistent style)
@Component({/* ... */})
export class Checkbox {
  disabled = input(false);
  // Signal-based style for outputs (proposed)
  toggled = output<boolean>();
}
```

Emitting events remain unchanged and continue to use the `emit` method.

### 4. Model Inputs: Simplifying Two-Way Data Binding
Two-way data binding, a staple in Angular development, often involves setting up dedicated `@Input` and `@Output` properties with specific naming conventions.

The Signals API streamlines this process by introducing model inputs. These inputs allow you to directly define a signal within your component, eliminating the need for separate input and output properties. This not only reduces boilerplate code but also clarifies the intent of the data being bound.

Here's an example showcasing the simplification:

```ts
// Before (using @Input and @Output)
@Component({
    // ...
    template: '<cool-checkbox [(checked)]="isAdmin" />'
})
export class Profile {
  isAdmin = false;
}

// After (using model input)
@Component({/* ... */})
export class CoolCheckbox {
  checked = model(false);
}

// After (using model input, with signal 
// change in Profile component)
@Component({/* ... */})
export class Profile {
  // Create a signal for isAdmin property
  isAdmin = signal(false); 
}
```

This new approach provides a writable signal within your component, allowing you to directly update the bound value and propagate changes seamlessly.

### Conclusion

By incorporating these Signals API features, you can enhance the readability, maintainability, and overall reactivity of your Angular applications. Remember, this API is currently in developer preview, so stay tuned for further updates and potential changes as it evolves.