• Angular
  • React
  • NextJs
  • Sass

Angular Signals Example

By Webrecto, September 27, 2023

In this article, we will learn about Angular's new feature signals, which are introduced in Angular version 16. It is imported signals from @angular/core and interop packages.

Angular Signals Example

What is a Signal in Angular?

The Angular Signal is a special type of function that holds a value that can change over time and it returns the current value. The Signals are used to track changes to data and manage the state in the application.

The Signal function is especially can affect many parts in the application like data flow, change detection mechanism, and component lifecycle. It also makes code more reactive and improves application performance.

Syntax

// Signature of signal function
signal(initialValue: T, options?: CreateSignalOptions): WritableSignal

The Signal function is a TypeScript function that creates a Signal. The function takes two arguments one is initialValue and the other is options.

initialValue: This argument represents the initial value of the Signal and it can be any type T.

options: This argument is an object of the CreateSignalOptions type, that includes an equals method for comparing two values of type T.

The signal function returns a WritableSignal.

Where are signal useful?

  • 1: The Signals are a way to create a one-way data flow in an Angular application.
  • 2: Signals implements the reactive programming paradigm in the application and allows to writing of more reactive code.
  • 3: We use them in a service to share state across components.
  • 4: Angular Signals adds three reactive primitives to Angular 16+, It allows the creation of reactive apps without the use of RxJs.
  • 5: In the Angular application, some signals can be changed directly.
  • 6: We can use them in components to track the local component state.

How to Create a Signal in Code

firstName = signal<string>('Mohit');
lastName = signal<string>('Singh');

employeeName = computed(() => `${this.firstName()} ${this.lastName()}`);

// call setEmployeeName method from template
setEmployeeName(fName: string, lName: string) {
    this.firstName.set(fName);
    this.lastName.set(lName);
}

In the above code, we create and initialize a signal using the signal constructor function. We can provide optionally generic type parameters to define the signal's data type. The signal can be a string, number, array, object, or any data type.

Here we pass the string value first name and last name in both signal functions and assign the updated signal value in a variable. The signal function watches any changes in name by the user, It automatically updates the name.

How to Read a Signal Value

Here we read the updated signal variable in the template. The employeeName is the signal variable and it collects updated value. We use employeeName signal in the template inside the open and closing parentheses.

<div>Emplyee Name is: {{ employeeName() }}</div>
<button (click)="setEmployeeName('Ashutosh', 'Rai')">Click</button>

In the above code, we are using the signal function to change the employee name through a button click. In the button I bind click event which name is setEmployeeName() and pass the first and last name in the parameter. In the component file, the click event method sets both parameter values to the signals for the update of the employee name.

How to Change the Value of a Signal

The signal uses the set() method, that replaces the value of a signal with a new value.

this.firstName.set(fName);

In the above code, firstName is a signal and holds the old value. When calling the click event from the template, we use the set() method with signal and pass a new value for the set.

What is Computed Signal in Angular

The computed() function creates a new signal that depends on other signals. It is imported from '@angular/core'.

computed(computation: () => T, options?: CreateComputedOptions): Signal

The computed signal derives a reactive value from an expression and returns Signal.

computed() creates a memoizing signal, which calculates its value from the values of some number of input signals.

employeeName = computed(() => `${this.firstName()} ${this.lastName()}`);

The computed function returns a Signal, which is not a WritableSignal. We can not modify it manually with the help of methods such as set(), update(), or mutate. The computed function is updated automatically when any changes in dependent signals

How to Use an Effect

The effect() function can be called within other functions. Some side effect comes in code when updating or changing the signal, so we can use the effect() function to handle the side effects.

export function effect(
    effectFn: () => EffectCleanupFn | void, options?: CreateEffectOptions): EffectRef

The effect() function returns an EffectRef, which is a global reactive effect that can be manually destroyed.

We can use the effect() function inside the constructor or other startup code. We can add multiple signals to the inside of the effect function. The function inside the effect will re-evaluate with any change that occurs in the signals called inside it.

constructor() {
    effect(() => console.log('Name changed:', this.employeeName()));
  }

Complete Example

In this below example, we are using signal function to update employee name and total employee salary.

employee.component.ts

import { Component, signal, computed, effect } from '@angular/core';  

@Component({
  selector: 'employee-info',
  templateUrl: './employee.component.html'  
})
export class EmployeeComponent  { 
  firstName = signal('Mohit');
  lastName = signal('Singh');

  employeeName = computed(() => `${this.firstName()} ${this.lastName()}`);

  constructor() {
    effect(() => console.log('Name changed:', this.employeeName()));
  }

  setEmployeeName(fName: string, lName: string) {
    this.firstName.set(fName);
    this.lastName.set(lName);
  }

  employee = [
    { name: 'Mohan', salary: 5000 },    
    { name: 'Ramesh', salary: 15000 },    
    { name: 'Vijay', salary: 12000 },  
  ];
  employeeList = signal(this.employee);
  totalSalary = computed(() => {
    return this.employeeList().reduce((name, salary) => name + salary.salary, 0);
  });

  removeItem(emp: any) {
    // Update the employeeList signal by removing the selected item
    this.employeeList.set(this.employeeList().filter((i) => i !== emp));
  };
}

employee.component.html

<p>Emplyee Name is: {{ employeeName() }} </p>

<button (click)="setEmployeeName('Ashutosh', 'Rai')">Click</button>

<h3>Update Employee Total Salary</h3>
<ul>
    <li *ngFor="let emp of employee">
      {{emp.name}} - {{emp.salary}}
      <button (click)="removeItem(emp)">Remove Salary</button>
    </li>
</ul>
Total Employee Salary: <b>{{totalSalary()}}</b>

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  styleUrls: ['./app.component.css'],
  template: `
    <h2>Angular Signals example:: webrecto.com</h2>
    <employee-info></employee-info>
  `,
})
export class AppComponent {

}

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { EmployeeComponent } from './employee/employee.component';

@NgModule({
  declarations: [
    AppComponent,
    EmployeeComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Find the print screen of the output.

Angular Signals Example

Reference

Download Source Code