---
title: "Head Start with Angular Signals: A Basic Overview"
date: "2023-09-26"
slug: "head-start-with-angular-signals-a-basic-overview"
author: "Dany Paredes"
canonical: "https://danywalls.com/head-start-with-angular-signals-a-basic-overview"
description: "Since Angular 16, I have heard a lot about Signals, the @angular/team did great work listening to the community and improving the Signals API with Rxjs interop. Yesterday I was talking with my friend Juan Berzosa he hadn't played with Signals yet, So..."
---

Since Angular 16, I have heard a lot about [Signals](https://angular.io/guide/signals), the [@angular/team](https://github.com/angular/angular) did great work [listening to the community](https://github.com/angular/angular/discussions/49685) and improving the Signals API with [Rxjs interop](https://angular.io/guide/rxjs-interop).

Yesterday I was talking with my friend @[Juan Berzosa](@juanberzosa) he hadn't played with Signals yet, So I decided to write a small article that explained what are signals and how they help angular to have a better reactive and change detection system.

Before diving into Signals, let's ask ourselves why the following code doesn't respond to changes ?

We have the `CardsService` , with three properties `cards`, `cardsLeft`, `lastClient` and the add method. The method `add`, push a new value into the cards array, decreases the value of `cardsLeft` and set the holder name.

```typescript
@Injectable({ providedIn: 'root' })
export class CardsService {
  cards: Array<Card> = [
    {
      id: '1',
      holder: 'Dany',
      status: 'Active',
    },
    {
      id: '2',
      holder: 'Edgar',
      status: 'Active',
    },
  ];

  cardsleft: number = 3;
  lastClient = 'No clients yet!';

  add(holder: string) {
    const card = {
      id: Math.random().toFixed(),
      holder,
      status: 'pending',
    };
    this.cards = [...this.cards, card];
    this.cardsleft--;
    this.lastClient = `Thanks ${holder}!!`;
    console.log(this.cards, this.lastClient, this.cardsleft);
  }
}
```

In the component, we use cardService properties to display information in the template, showing the cards list from cardService and the values from cardLeft and lastClient.

The save button calls the add method from the service, which pushes and changes the array and properties, but why isn't it reflected in my component?

```typescript

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [CommonModule],
  template: `
   <h3>We have {{cardLeft}} cards </h3>
   <p>{{lastClient}}</p>
   <input type="text" #holder />
   <button (click)="add(holder)">Save</button>
   <div *ngFor="let card of cards">
   {{card.holder}} {{card.id}}
   </div>
  `,
})
export class App {
  private cardsService = inject(CardsService);

  cards = this.cardsService.cards;
  cardLeft = this.cardsService.cardsleft;
  lastClient = this.cardsService.lastClient;

  add(holder: HTMLInputElement) {
    this.cardsService.add(holder.value);
    holder.value = '';
  }
}
```

Feel free to play:

[Link](https://stackblitz.com/edit/stackblitz-starters-v6a9ed) 

The service modifies the properties, but those changes are not reflected in my component. These properties don't notify Angular that they have changed. Some solutions include:

* Reasign the values.
    
* Use a reactive approach with Rxjs.
    

What if I told you we can write a real reactive code and it reacts to changes, easily without Rxjs or reassigning values?

## Reactivity, Change Detection, and NgZone

Do you know how Angular detects changes? Angular listens to events or data changes in the app by using Change detection in detection across the entire application using NgZone.

The NgZone makes change detection easier in Angular apps, but when the app gets larger, ZoneJS can slow it down and impact performance. In fact, we take some approaches to address this issue:

* Using OnPush change detection
    
* Using running code outside Angular with `ngZone.runOutsideAngular(() => ...)`, to make change detection happen less often and speed things up.
    

However, another side effect is that ngZone doesn't indicate which component changed, only that something occurred in the app. Angular must check all components to identify the one that changed.

> To learn more about Change Detection, watch video by Decoded Frontend.

[Link](https://www.youtube.com/watch?v=Ys7xdebd66Y) 

The Angular team reevaluated how reactivity works to provide a building block and an excellent solution, keeping the following points in mind:

* Know about which and when the application state changes.
    
* Allow developers to indicate where it is used and when it changes.
    
* Let Angular automatically update whatever depends on that value.
    
* Gain fine-grained control of updates.
    

Taking those points into consideration, the Angular team introduced [Angular Signals](https://angular.io/guide/signals).

> It's ready for use in developer preview starting from Angular version 16.

## Signals

Signals enable fine-grained reactivity into Angular's core, providing a new way to recognize when our data has changed. They enhance Angular's change detection by running it only for the component change the data, which improves the efficiency of your Angular application and makes our code more reactive.

Ok, but what is a Signal, signal is a value accompanied by change notifications, which offers updates to its references and can be utilized in components for reading values, services, or templates and everywhere.

Signals offer three primary types, known as reactive primitives. These building blocks are provided by Angular, enabling us to work with Signals effectively. The three main types are: [Writable Signals](https://angular.io/guide/signals#writable-signals), [Computed Signals](https://angular.io/guide/signals#computed-signals), and [Effects](https://angular.io/guide/signals#effects).

### Writable Signals

We declare a signal variable using `signals()` function, and set an initial value. It holds a variable and notifies angular when it occurs.

```typescript
quantity = signal<number>(3000)
```

To read the value of the 'quantity' signal, we use parentheses () to access the value.

```typescript
payment() //3000
```

When we create a variable using the 'signal' function, it becomes writable and provides methods for working with it, such as 'set', 'update', or 'mutate'.

#### Set:

The `set` method replaces the value of a signal with a new value. When the signal is updated, the code notifies consumers that the signal has changed.

```typescript
   payment.set(3000);
   payment() // 3000
```

#### Update:

The `update()` method changes the signal using its present value. Give the update method a simple function. This function offers the current signal value for you to change as required.

```typescript
typescript payment.update(p => p + 100) payment(); //3100
```

#### mutate:

Thanks to @[Rainer Hahnekamp](@rainerhahnekamp) , I got the notice Angular Team has marked Signals as stable for version 17 and removed the mutate method from public API.

> My secret trick to stay updated on what's happening in the Angular world is ngnews in [YouTube](https://www.youtube.com/@ng-news) and [Twitter (x)](https://twitter.com/_ng_news).

> [https://github.com/angular/angular/commit/c7ff9dff2c14aba70e92b9e216a2d4d97d6ef71e](https://github.com/angular/angular/commit/c7ff9dff2c14aba70e92b9e216a2d4d97d6ef71e)

![Image](https://pbs.twimg.com/media/F7xRr7GX0AAAstD?format=jpg&name=medium align="left")

<s>The </s> `mutate()` <s>method modifies the content of a signal value, not the signal value itself. Use it with arrays to modify array elements, and objects to modify object properties.</s>

<s>The consumers are not notified about the signal being changed, it must read the new signal value.</s>

```typescript
demo = signal<any>({ id: 1 }); 
demo.mutate(p => { id: 2 })
```

### Computed Signals:

A computed signal is a variable that reflects changes between signals and read-dependent signals, and only changes if the values it depends on change, they are only calculated once even if used in three different places.

> Computed Signals are read-only, they cannot be modified with 'set', 'update', or 'mutate'.

```typescript
soldOut = computed(() => this.cardSlots() <= 0);
```

### Effect

Effects are functions that execute when the values of the signals they depend on change. We can tell Angular to run a function that uses values from signals, and Angular will automatically rerun the code-associated signals change.

```typescript
 effect(() => {
      if (this.soldOut()) {
        this.title = 'Bank Closed';
      }
  });
```

## Refactor With Signals

We already know what a signal is, as well as the three types: `WritableSignal`, `Computed`, and `effect`. With this knowledge, we can refactor our code.

First, we turn the `cards` array into a Signal cards array, `cardSlot` and `lastClient` in a writable signal.

```typescript
  cards = signal<Card[]>([
    {
      id: '1',
      holder: 'Dany',
      status: 'Active',
    },
    {
      id: '2',
      holder: 'Edgar',
      status: 'Active',
    },
  ]);


  cardSlots = signal<number>(3);
  lastClient = signal('No clients yet!');
```

Next, declare a computed to react to `cardSlots` changes.

```typescript
 soldOut = computed(() => this.cardSlots() <= 0);
```

In the `add` method updates the signals props with `set` and `update` methods.

```typescript
  add(holder: string) {
    const card = {
      id: Math.random().toFixed(),
      holder,
      status: 'pending',
    };
    this.cards.update((p) => [...p, card]);
    this.cardSlots.update((p) => p - 1);
    this.lastClient.set(`Thanks ${holder}`!!);
  }
```

In the component, add a reference to those variables.

```typescript
 cards = this.cardsService.cards;
  cardSlots = this.cardsService.cardSlots;
  soldOut = this.cardsService.soldOut;
  lastClient = this.cardsService.lastClient;
```

In the HTML markup, access the signal value by using parentheses `().`

```typescript
    <h1>{{title}}</h1>
    <h3>We have {{cardSlots()}} slots </h3>
    <p>{{lastClient()}}</p>
    <input type="text" #holder [disabled]="soldOut()"/>
    <button (click)="add(holder)"
     [disabled]="soldOut()">Save</button>

    <div *ngFor="let card of cards()">
    {{card.holder}} {{card.id}}
    </div>
```

Finally, utilize the `effect` in the constructor, reading the 'soldOut' signal to update the title:

```typescript
  constructor() {
    effect(() => {
      if (this.soldOut()) {
        this.title = 'Bank Closed';
      }
    });
  }
```

The final code looks like:

[Link](https://stackblitz.com/edit/stackblitz-starters-hwywe4) 

## Conclusion

Done! We have a basic overview of how to make your apps reactive using Signals. Signals are game-changers in Angular bringing fine-grained reactivity, efficiency, and performance improvements to our apps.

But what about RxJS? How do Signals impact it? I will discuss this in another article. Meanwhile, I recommend checking out the [official documentation](https://angular.io/guide/signals) to learn more about it.

Happy coding!

_Photo by [Carlos Alberto Gómez Iñiguez](https://unsplash.com/@iniguez?utm_source=unsplashx&utm_medium=referral) on [Unsplash](https://unsplash.com/?utm_source=unsplashx&utm_medium=referral)_

