Codecademy Logo

Angular Signals

Angular Signals

In Angular, signals are used to manage reactive state by storing a value and automatically updating any dependent components or views when the value changes.

import { WritableSignal, signal } from '@angular/core';
export class ExampleComponent {
count: WritableSignal<number> = signal(0);
increment() {
this.count.update(value => value + 1);
}
}

Angular signal() Function

In Angular, the signal() function is used to create a signal with an initial value that can be updated and observed reactively.

import { signal, WritableSignal } from '@angular/core';
export class ExampleComponent {
count: WritableSignal<number> = signal(0);
increment() {
this.count.update(n => n + 1);
}
}

Accessing a Signal’s Value

In Angular, a signal’s current value can be accessed by calling its getter function ().

import { signal, WritableSignal } from '@angular/core';
export class ExampleComponent {
count: WritableSignal<number> = signal(0);
logCurrentValue() {
console.log(this.count()); // accessing the current value of count signal
}
increment() {
this.count.update(n => n + 1);
}
}

Angular Signal set() Function

In Angular, the set() method directly assigns a new value to a signal, completely replacing the previous value. Unlike update(), set() doesn’t provide access to the current value during the assignment.

import { signal, WritableSignal } from '@angular/core';
export class ExampleComponent {
theme: WritableSignal<string> = signal('light');
toggleTheme() {
this.theme.set('dark');
}
reset() {
this.theme.set('light');
}
}

Angular Signal update() Function

In Angular, the update() method changes a signal’s value by applying a function that uses the current value to calculate a new value. This approach ensures safe access to the current value when calculating the new state.

import { signal, WritableSignal } from '@angular/core';
export class ExampleComponent {
count: WritableSignal<number> = signal(0);
increment() {
this.count.update(currentValue => currentValue + 1);
}
double() {
this.count.update(currentValue => currentValue * 2);
}
}

Angular Signal computed() Function

In Angular, the computed() function creates a signal that derives its value from other signals, automatically updating whenever its dependencies change. Dependencies are automatically tracked when signals are accessed (using parentheses) within the computed function.

import { signal, computed, WritableSignal, Signal } from '@angular/core';
export class ExampleComponent {
count: WritableSignal<number> = signal(0);
multiplier: WritableSignal<number> = signal(2);
result: Signal<number> = computed(() => this.count() * this.multiplier());
increment() {
this.count.update(n => n + 1);
}
changeMultiplier() {
this.multiplier.update(n => n + 1);
}
}

Angular Signal effect() Function

In Angular, the effect() function executes code automatically whenever its signal dependencies change. Effects are used for performing tasks in response to signal changes (like updating the DOM or making API calls) and don’t return values. Like computed signals, they automatically track any signals that are read within their function body.

import { signal, effect, WritableSignal } from '@angular/core';
export class ExampleComponent {
userName: WritableSignal<string> = signal('Guest');
constructor() {
effect(() => {
document.title = `Welcome, ${this.userName()}`;
});
}
updateName(newName: string) {
this.userName.set(newName);
}
}

Angular Signal untracked() Function

In Angular, the untracked() function reads a signal’s value without adding it as a dependency in effects or computed signals. This means changes to signals read within untracked() won’t trigger effects or computed signals to update.

import { signal, effect, untracked, WritableSignal } from '@angular/core';
export class ExampleComponent {
count: WritableSignal<number> = signal(0);
limit: WritableSignal<number> = signal(5);
constructor() {
effect(() => {
// This creates a dependency - effect runs when count changes
console.log(`Count is: ${this.count()}`);
// Using untracked() - effect won't run when limit changes
console.log(`Limit is: ${untracked(() => this.limit())}`);
});
}
}

Angular Signal Input

In Angular, the input() function creates signal-based component inputs that update automatically when their values change. These inputs are read-only signals that can be accessed in the component’s template or class using the signal getter syntax.

import { Component, input } from '@angular/core';
@Component({
selector: 'app-child',
template: `<p>Value: {{ value() }}</p>`
})
export class ChildComponent {
value = input<number>();
}
@Component({
selector: 'app-parent',
template: `<app-child [value]="10" />`
})
export class ParentComponent {}

Angular Signal model() Function

In Angular, the model() function creates a special signal that enables two-way data binding by combining input and output functionality. Changes can flow both from parent to child and from child back to parent.

import { Component, model, ModelSignal } from '@angular/core';
// Child component
@Component({
selector: 'app-child',
template: '<button (click)="increment()">Increment</button>'
})
export class ChildComponent {
value = model<number>(0);
increment() {
this.value.update(val => val + 1);
}
}
// Parent component
@Component({
selector: 'app-parent',
template: '<app-child [(value)]="parentValue()"></app-child>'
})
export class ParentComponent {
parentValue = signal(10);
}

Angular Signal viewChild() Function

In Angular, the viewChild() function creates a signal that references a child element or component using a template reference variable, automatically updating when the referenced element or component changes.

import { Component, viewChild, ElementRef } from '@angular/core';
@Component({
selector: 'app-parent',
template: `<div #myDiv></div>`
})
export class ParentComponent {
myDiv = viewChild<ElementRef>('myDiv');
}

Angular Signal contentChild() Function

In Angular, the contentChild() function creates a signal that references content projected into a component through ng-content, automatically updating when the projected content changes.

import { Component, contentChild, ElementRef } from '@angular/core';
@Component({
selector: 'app-container',
template: `<ng-content></ng-content>`
})
export class ContainerComponent {
content = contentChild<ElementRef>('projectedContent');
}
@Component({
selector: 'app-parent',
template: `
<app-container>
<p #projectedContent>Projected Content</p>
</app-container>
`
})
export class ParentComponent {}

Angular Signals vs Observables

In Angular, signals and observables serve different purposes in reactive programming. Signals manage a single value that updates synchronously, providing direct access to the current state. Observables, in contrast, manage streams of values over time, with built-in support for asynchronous data flow.

import { Component, signal } from '@angular/core';
@Component({
selector: 'app-example',
template: `
<div>Count: {{ count() }}</div>
<button (click)="increment()">Add</button>
`
})
export class ExampleComponent {
// Signal: Always has a current value
count = signal(0);
increment() {
this.count.update(n => n + 1);
}
}

Learn more on Codecademy