Angular Signals: Part 1 — Introduction
In this article, I will explain the concept of Signals in Angular.
Signals are ready for production starting from Angular v18. I will be publishing a series on advanced concepts in signals. In this article, I am explaining the basic concepts of Signals.
I will cover:
- How to define a Signal.
- How to display a Signal’s value in a template.
- How to update a Signal’s value with set().
- How to update a Signal’s value with update().
- Compute Signal.
- Effect.
1. Define Signal:
we are defining 2 signal variables
- counter is of type number.
- customer is of type CustomerI.
2. Display Signal’s value in a Template:
we need to use parentheses to display value in signal.
3. Update signals value using set()
We need to use set() method if we want to assign new value to signal.
4. Update signals value using update()
Within the update()
method, we need to pass an anonymous function. This function takes the current value as a parameter, allowing us to implement the logic to update the value.
this.counter.set(this.counter() + 1);
is not recommended because it directly sets the value without considering the current state management best practices.this.counter.update((previousValue) => previousValue + 1);
is the correct approach. Here,update()
accepts an anonymous function that takes the previous value (previousValue
) as a parameter and returns the new value after applying the increment logic. This method ensures that the state is updated correctly and is more maintainable.
5. Computed Value:
In this example:
doubleCounter
is a new signal derived from thecounter
signal.- The
computed()
function takes a function as its argument. This function calculates the new value fordoubleCounter
based on the current value ofcounter
. - Whenever
counter
is updated, the computed function re-executes, ensuring thatdoubleCounter
always reflects the current state ofcounter
multiplied by 2.
6. Effect:
In this example:
- Inside the constructor, we define an effect using the
effect()
function. - The
effect()
function takes an anonymous function as an argument, which callsthis.counter()
. - This effect will execute whenever the
counter
signal is updated. - Within the effect, you can perform any side effects needed, such as logging, updating the UI, or triggering other actions.
import { Component, computed, effect, signal } from '@angular/core';
@Component({
selector: 'app-cart',
standalone: true,
template: `
<p>Counter:- {{counter()}}</p>
<p>Double Counter:- {{doubleCounter()}}</p>
<p>Customer Name:-{{customer().name || 'N/A'}}</p>
<p>Customer ID:-{{customer().id || 'N/A'}}</p>
<button (click)="updateCustomer()">Update Customer</button>
<button (click)="increment()">Increment</button>
`,
})
export class CartComponent {
counter = signal<number>(0);
customer = signal<CustomerI>({ name: '', id: null });
doubleCounter = computed(() => this.counter() * 2);
constructor() {
effect(() => {
this.counter();
// we can perform side effects here.
})
}
updateCustomer() {
this.customer.set({ name: 'Signal', id: 18 });
}
increment() {
// this.counter.set(this.counter() + 1); // Dont do this.❌
this.counter.update((previousValue) => previousValue + 1); //✅
}
}
Reference: https://angular.dev/guide/signals