Angular Services Encapsulation State Management
In Angular applications, getters and setters are powerful tools for data management. They help encapsulate private data, enforce validation rules, and control how components and services access or modify shared state. This leads to cleaner, safer, and more maintainable code across your app.
private and expose them using getters/setters.In TypeScript (and therefore Angular), getters and setters are defined using the get and set keywords inside a class. They look like methods but are used like properties.
// user.model.ts - basic getter/setter example
export class User {
private _firstName = '';
private _lastName = '';
get fullName(): string {
// Combine first and last name into a single readable value
return `${this._firstName} ${this._lastName}`.trim();
}
set fullName(value: string) {
// Simple parsing: split the string into first + last name
const [first, last] = value.split(' ');
this._firstName = first ?? '';
this._lastName = last ?? '';
}
}
Notice how fullName behaves like a normal property from the outside, but internally it runs logic to read or update the underlying fields.
A common pattern in Angular is to use a service as a single source of truth for shared data. Getters and setters protect that data.
// data.service.ts - central data store with guarded setter
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class DataService {
private _items: string[] = [];
get items(): string[] {
return [...this._items]; // Return a copy to prevent direct mutation from outside
}
set items(newItems: string[]) {
// Allow bulk updates only when the list is reasonably small
if (newItems.length <= 100) {
this._items = [...newItems];
} else {
console.warn('Too many items, maximum limit is 100.');
}
}
addItem(item: string) {
// Helper method for safely adding a single item
this._items.push(item);
}
}
Components consume the service by reading the getter and calling methods. They never touch the private data directly.
// inventory.component.ts - consuming the DataService in a view
import { Component } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'app-inventory',
template: `
<h2>Inventory List</h2>
<ul>
<li *ngFor="let item of dataService.items">{{ item }}</li>
</ul>
<button (click)="addNewItem()">Add Item</button>
`
})
export class InventoryComponent {
constructor(public dataService: DataService) {}
addNewItem() {
// Use the service API instead of mutating the array directly
this.dataService.addItem('New Product ' + (this.dataService.items.length + 1));
}
}
Getters can also compute values on the fly from underlying data, such as aggregating the total revenue of all orders.
// order.service.ts - exposing orders and computed totalRevenue
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class OrderService {
private _orders: { id: number; total: number }[] = [];
get orders() {
// Expose the raw list (could be cloned if needed)
return this._orders;
}
get totalRevenue(): number {
// Calculate the sum of all order totals whenever accessed
return this._orders.reduce((sum, order) => sum + order.total, 0);
}
addOrder(order: { id: number; total: number }) {
// Central place to validate and push new orders
this._orders.push(order);
}
}
_items private. The getter returns a copy so components cannot accidentally mutate the internal array.items validates bulk updates (max 100 items) before replacing the list.dataService.items in the template and calls addItem() to add new products, keeping all logic inside the service.totalRevenue to calculate the sum of all orders whenever you read it, so you never have to manually recalculate it in components.products, orders, or notifications from a central service.cartTotal, isLoggedIn, or activeUserCount.BehaviorSubject if you need reactive streams of data in multiple components.UserService with firstName and lastName fields and a getter fullName that combines them.CartService setter to prevent negative product quantities or a cart size above a chosen limit.AnalyticsService with a computed getter activeUserCount that returns the total number of active users based on an internal array.