DEV Community

Cover image for Streamlining Communication: New Signals API in Angular 17.3
Sonu Kapoor for This is Angular

Posted on

Streamlining Communication: New Signals API in Angular 17.3

Introduction

Angular 17.3 introduces a developer preview of a new Signals API, a feature unveiled at the ngConf 2024 keynote by Jeremy Elbourn and Minko Gechev.

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:

// 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;
}
Enter fullscreen mode Exit fullscreen mode

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:

// 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>();
}
Enter fullscreen mode Exit fullscreen mode

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:

// 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>();
}
Enter fullscreen mode Exit fullscreen mode

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:

// 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); 
}
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (1)

Collapse
 
jangelodev profile image
João Angelo

Hi Sonu Kapoor,
Your tips are very useful
Thanks for sharing