Angular Tutorial menu

Angular Signals

A signal is a value that tells Angular when it changes, so the screen can update exactly where that value is used.

Creating a Signal

Import signal from @angular/core and give it a starting value:

Example

typescript
import { Component, signal } from "@angular/core";

@Component({
  selector: "app-water",
  template: `
    <p>Glasses of water today: {{ glasses() }}</p>
    <button (click)="drink()">Drink one</button>
    <button (click)="reset()">Reset</button>
  `,
})
export class Water {
  glasses = signal(0);

  drink() {
    this.glasses.update((g) => g + 1);
  }

  reset() {
    this.glasses.set(0);
  }
}
Output
Glasses of water today: 0
(after 3 clicks on Drink one)
Glasses of water today: 3

To read a signal, call it like a function: glasses(). This works in templates and in TypeScript code.

Changing a Signal

MethodUse it whenExample
set(value)You know the new valuename.set("Ayesha")
update(fn)The new value depends on the old onecount.update(c => c + 1)

Signals with Objects and Arrays

Treat objects and arrays in signals as read-only. Create a new one when you change something:

Example

typescript
import { Component, signal } from "@angular/core";

interface Item {
  id: number;
  name: string;
}

@Component({
  selector: "app-shopping",
  template: `
    <button (click)="add()">Add Atta</button>
    <ul>
      @for (item of items(); track item.id) {
        <li>{{ item.name }}</li>
      }
    </ul>
  `,
})
export class Shopping {
  items = signal<Item[]>([{ id: 1, name: "Rice" }]);

  add() {
    this.items.update((list) => [...list, { id: Date.now(), name: "Atta" }]);
  }
}

If you push into the same array, the signal does not know anything changed.

computed()

A computed signal gets its value from other signals. Angular recalculates it only when those signals change.

Example

typescript
import { Component, signal, computed } from "@angular/core";

@Component({
  selector: "app-fee",
  template: `
    <p>Months: {{ months() }}</p>
    <p>Total fee: Rs {{ total() }}</p>
    <p>{{ discountNote() }}</p>
    <button (click)="months.update((m) => m + 1)">Add a month</button>
  `,
})
export class Fee {
  months = signal(2);
  monthlyFee = signal(3000);

  total = computed(() => this.months() * this.monthlyFee());
  discountNote = computed(() =>
    this.months() >= 3 ? "You get 10% off!" : "Join for 3 months to get a discount."
  );
}
Output
Months: 2
Total fee: Rs 6000
Join for 3 months to get a discount.
(after 1 click)
Months: 3
Total fee: Rs 9000
You get 10% off!

Computed signals are read-only. You cannot call set on them.

effect()

An effect runs code whenever the signals it reads change. Use it for side effects, such as saving to local storage or logging.

Example

typescript
import { Component, signal, effect } from "@angular/core";

@Component({
  selector: "app-theme",
  template: `<button (click)="toggle()">Theme: {{ theme() }}</button>`,
})
export class Theme {
  theme = signal("light");

  constructor() {
    effect(() => {
      console.log("Theme is now", this.theme());
      localStorage.setItem("theme", this.theme());
    });
  }

  toggle() {
    this.theme.update((t) => (t === "light" ? "dark" : "light"));
  }
}
Output
Theme is now light
Theme is now dark

Effects must be created in an injection context, such as the constructor.

Do not use effect() to copy one signal into another. If a value can be calculated, use computed() instead. Effects are for talking to the outside world.

Why Signals?

  • Angular knows exactly which parts of the page depend on which values
  • Your code is simple: read with (), write with set or update
  • Signals work everywhere: components, services and inputs (input() returns a signal)

Exercise

Exercise

How do you read the current value of a signal called price?

Learn Angular with a teacher

Join the Full Stack Development course at Workownix, online or in Orangi Town, Karachi, and get a certificate.

See the course Ask on WhatsApp