← Back to Chapters

Getter/Setter in Angular Services

? Getter/Setter in Angular Services

⚡ Quick Overview

In Angular, services are commonly used to store and share data across components. By adding getters and setters to a service, you can:

  • Keep data encapsulated behind a controlled API.
  • Perform validation whenever data changes.
  • Ensure consistent access to shared state.
  • Bind data directly in templates using Angular features like [(ngModel)].

? Key Concepts

  • Private fields: Use a private property (e.g. private _username) to store data.
  • Getter: Exposes a read-only view of the private field.
  • Setter: Controls how the value is updated (e.g. trimming, validating, transforming).
  • Service as a single source of truth: Components read/write through the service only.
  • Two-way binding: Components can bind inputs directly to service properties.

? Syntax & Theory

A typical pattern for getters/setters in an Angular service looks like this:

? View Generic Getter/Setter Pattern
// Generic service pattern using getter and setter
import { Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class ExampleService {
  private _value: string = '';

  get value(): string {
    return this._value;
  }

  set value(newValue: string) {
    this._value = newValue.trim();
  }
}

The get and set keywords make value look like a normal property when used in components, but under the hood you can keep all your logic centralized in the service.

? Code Examples

? 1) UserService with Getter and Setter

This service stores a username and trims extra spaces whenever it is updated.

? View Code Example
// user.service.ts - manage a username with getter and setter
import { Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class UserService {
  private _username: string = '';

  get username(): string {
    return this._username;
  }

  set username(value: string) {
    this._username = value.trim();
  }
}

? 2) Using the Service in a Component

The component injects UserService and binds the template input directly to userService.username.

? View Code Example
// profile.component.ts - bind template to service property
import { Component } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-profile',
  template: `
    <h2>Hello {{ userService.username }}</h2>
    <input [(ngModel)]="userService.username" placeholder="Enter Username">
  `
})
export class ProfileComponent {
  constructor(public userService: UserService) {}
}

? 3) SettingsService with Validation in Setter

Here, the setter validates the theme before updating it. Only 'light' and 'dark' are accepted.

? View Code Example
// settings.service.ts - validate theme values in the setter
import { Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class SettingsService {
  private _theme: string = 'light';

  get theme(): string {
    return this._theme;
  }

  set theme(value: string) {
    if (['light', 'dark'].includes(value)) {
      this._theme = value;
    } else {
      console.warn('Invalid theme value, keeping previous setting.');
    }
  }
}

? Live Output / Explanation

What Happens in the App?

  1. When the user types a name into the input in ProfileComponent, Angular updates userService.username using the setter.
  2. The setter trims extra spaces (e.g. " Meghraj " becomes "Meghraj"), keeping the stored value clean.
  3. The getter is used whenever the template reads {{'{{ userService.username }}'}}, so the heading always shows the latest username: Hello Meghraj.
  4. In the SettingsService, if someone tries to set theme to "blue", the setter rejects it and logs a warning instead of breaking the app.

In summary, components stay simple: they just read/write properties. All rules and checks live in the service.

✅ Tips & Best Practices

  • Use services with getters/setters for shared state like user data, settings, or app configuration.
  • Combine getters with BehaviorSubject or Observable when you need reactive updates (e.g. a getter returning theme$).
  • Keep logic inside getters/setters lightweight; move heavy processing to separate methods.
  • Prefer narrow, focused services so each one is easy to test and reason about.
  • Treat the service as the single source of truth for that piece of state.

? Common Use Cases

  • Authentication: Getter for isLoggedIn, setter for token.
  • Theme & Layout: Getter for current theme, setter validating allowed modes.
  • Cart / Orders: Setter ensuring quantities are positive and stock-safe.
  • Feature Flags: Getter to check if a feature is enabled, setter to update configuration.

? Try It Yourself

  • Create an AuthService with:
    • a getter isLoggedIn that returns true if a valid token exists,
    • a setter token that validates basic JWT format before storing it.
  • Build a CartService where a setter ensures item quantities are never negative and caps them at a maximum limit.
  • Extend the SettingsService to include:
    • a setter for theme (already done), and
    • a getter isDarkMode that returns true when the current theme is 'dark'.
  • Refactor an existing component that directly manipulates state into using a service with getters/setters instead.