Skip to main content
The SettingsService manages application-wide settings using Angular signals with automatic persistence to localStorage.

Import

import { SettingsService } from '@jet/services/settings/settings.service';
import { Settings } from '@jet/interfaces/settings.interface';

Usage

Read Settings

import { inject, Component, Signal } from '@angular/core';
import { SettingsService } from '@jet/services/settings/settings.service';
import { Settings } from '@jet/interfaces/settings.interface';

export class AppComponent {
  readonly #settingsService = inject(SettingsService);
  
  readonly settings: Signal<Settings> = this.#settingsService.settings;

  ngOnInit() {
    // Read current settings
    const currentSettings = this.settings();
    console.log('Color scheme:', currentSettings.colorSchemeOption);
    console.log('Language:', currentSettings.languageOption);
  }
}

Update Settings

updateColorScheme(mode: 'light' | 'dark') {
  this.#settingsService.updateSettings({
    colorSchemeOption: {
      mode,
      variant: 'auto'
    }
  });
}

updateLanguage(code: string) {
  this.#settingsService.updateSettings({
    languageOption: {
      code,
      directionality: code === 'ar' ? 'rtl' : 'ltr'
    }
  });
}

Access Directionality

export class LayoutComponent {
  readonly #settingsService = inject(SettingsService);
  
  readonly directionality = this.#settingsService.directionality;

  ngOnInit() {
    // Computed signal for text direction
    const direction = this.directionality();
    console.log('Text direction:', direction); // 'ltr' or 'rtl'
  }
}

Reactive Templates

<div [dir]="settingsService.directionality()">
  <p>Current theme: {{ settings().colorSchemeOption.mode }}</p>
  <p>Language: {{ settings().languageOption.code }}</p>
</div>

Properties

settings

Read-only signal containing the current application settings.
type
Signal<Settings>
Reactive signal that emits when settings change
Source: /home/daytona/workspace/source/src/app/services/settings/settings.service.ts:51
public get settings(): Signal<Settings> {
  return this.#settings.asReadonly();
}
Example:
const currentSettings = this.settingsService.settings();

// Use in computed signals
const isDarkMode = computed(() => 
  this.settingsService.settings().colorSchemeOption.mode === 'dark'
);

// Use in effects
effect(() => {
  const settings = this.settingsService.settings();
  console.log('Settings changed:', settings);
});

directionality

Computed signal for the current text directionality (LTR/RTL).
type
Signal<'ltr' | 'rtl'>
Computed signal derived from language settings
Source: /home/daytona/workspace/source/src/app/services/settings/settings.service.ts:24
public readonly directionality: Signal<Settings['languageOption']['directionality']>;

// Computed as:
this.directionality = computed(() => this.#settings().languageOption.directionality);
Example:
// In component
const direction = this.settingsService.directionality();

// In template
<div [dir]="settingsService.directionality()">
  <!-- Content automatically flips for RTL languages -->
</div>

// In CSS-in-JS
const styles = computed(() => ({
  textAlign: this.settingsService.directionality() === 'rtl' ? 'right' : 'left'
}));

Methods

updateSettings

Updates application settings with partial updates and persists to localStorage.
partialSettings
Partial<Settings>
required
Object containing the settings to update
partialSettings.colorSchemeOption
ColorSchemeOption
Color scheme configuration
partialSettings.languageOption
LanguageOption
Language and directionality configuration
return
void
This method does not return a value. Settings are updated reactively.
Source: /home/daytona/workspace/source/src/app/services/settings/settings.service.ts:55
public updateSettings(partialSettings: Partial<Settings>): void {
  this.#settings.update((settings) => ({ ...settings, ...partialSettings }));
}
Example:
// Update only color scheme
this.settingsService.updateSettings({
  colorSchemeOption: { mode: 'dark', variant: 'auto' }
});

// Update only language
this.settingsService.updateSettings({
  languageOption: { code: 'es', directionality: 'ltr' }
});

// Update multiple settings
this.settingsService.updateSettings({
  colorSchemeOption: { mode: 'light', variant: 'custom' },
  languageOption: { code: 'ar', directionality: 'rtl' }
});

Type Definitions

Settings Interface

export interface Settings {
  colorSchemeOption: ColorSchemeOption;
  languageOption: LanguageOption;
}
Source: /home/daytona/workspace/source/src/app/interfaces/settings.interface.ts:4

ColorSchemeOption

interface ColorSchemeOption {
  mode: 'light' | 'dark' | 'auto';
  variant?: string;
}

LanguageOption

interface LanguageOption {
  code: string;
  directionality: 'ltr' | 'rtl';
}

Features

Automatic Persistence

Settings are automatically saved to localStorage whenever they change:
effect(() => {
  this.#loggerService.logEffectRun('settings');
  const settings = this.#settings();
  
  untracked(() =>
    this.#storageService.setLocalStorageItem(LocalStorageKey.Settings, settings)
  );
}, { debugName: 'settings' });

Default Settings

Settings are initialized with defaults merged with stored values:
const storedSettings = this.#storageService.getLocalStorageItem<Settings>(
  LocalStorageKey.Settings
);

this.#settings = signal({ ...DEFAULT_SETTINGS, ...storedSettings });

Reactive Updates

All changes propagate immediately through Angular signals:
// Component automatically re-renders when settings change
@Component({
  template: `<div>Current theme: {{ settings().colorSchemeOption.mode }}</div>`
})
export class ThemeComponent {
  readonly settings = inject(SettingsService).settings;
}

Computed Values

The service exposes computed signals for derived values:
// Directionality is computed from language settings
this.directionality = computed(() => 
  this.#settings().languageOption.directionality
);

Configuration

Default Settings

Define default settings in your constants:
// src/app/constants/default-settings.constant.ts
import { Settings } from '@jet/interfaces/settings.interface';

export const DEFAULT_SETTINGS: Settings = {
  colorSchemeOption: {
    mode: 'light',
    variant: 'auto'
  },
  languageOption: {
    code: 'en',
    directionality: 'ltr'
  }
};

Storage Key

Settings are stored using the Settings localStorage key:
enum LocalStorageKey {
  Settings = 'settings'
}

Best Practices

  1. Use partial updates - Only update the settings that changed
  2. Leverage computed signals - Create derived values for complex logic
  3. Read reactively - Use signal reads in templates and effects
  4. Validate updates - Ensure valid values before calling updateSettings()
  5. Type safety - Use TypeScript interfaces for all settings objects

Common Patterns

Theme Switcher Component

@Component({
  selector: 'app-theme-switcher',
  template: `
    <button (click)="toggleTheme()">
      {{ currentTheme() === 'dark' ? 'Light' : 'Dark' }} Mode
    </button>
  `
})
export class ThemeSwitcherComponent {
  readonly #settingsService = inject(SettingsService);
  
  readonly currentTheme = computed(() => 
    this.#settingsService.settings().colorSchemeOption.mode
  );

  toggleTheme() {
    const newMode = this.currentTheme() === 'dark' ? 'light' : 'dark';
    this.#settingsService.updateSettings({
      colorSchemeOption: { mode: newMode, variant: 'auto' }
    });
  }
}

Language Selector

export class LanguageSelectorComponent {
  readonly #settingsService = inject(SettingsService);
  
  readonly languages = [
    { code: 'en', name: 'English', dir: 'ltr' as const },
    { code: 'es', name: 'Español', dir: 'ltr' as const },
    { code: 'ar', name: 'العربية', dir: 'rtl' as const }
  ];

  selectLanguage(code: string, directionality: 'ltr' | 'rtl') {
    this.#settingsService.updateSettings({
      languageOption: { code, directionality }
    });
  }
}

Settings Form

export class SettingsFormComponent implements OnInit {
  readonly #settingsService = inject(SettingsService);
  
  settingsForm = new FormGroup({
    theme: new FormControl('light'),
    language: new FormControl('en')
  });

  ngOnInit() {
    const settings = this.#settingsService.settings();
    this.settingsForm.patchValue({
      theme: settings.colorSchemeOption.mode,
      language: settings.languageOption.code
    });
  }

  onSubmit() {
    const { theme, language } = this.settingsForm.value;
    
    this.#settingsService.updateSettings({
      colorSchemeOption: { mode: theme, variant: 'auto' },
      languageOption: {
        code: language,
        directionality: language === 'ar' ? 'rtl' : 'ltr'
      }
    });
  }
}

Dependencies

The SettingsService depends on:
  • LoggerService - For logging effect runs
  • StorageService - For localStorage persistence

Build docs developers (and LLMs) love