Centralized application settings management with localStorage persistence, reactive updates, and type-safe configuration for layout preferences, user data, and application-wide settings.
The core service for managing application settings with automatic localStorage persistence and reactive change notifications.
/**
* Settings management service with localStorage persistence
* Generic service supporting custom types for Layout, User, and App settings
*/
class SettingsService<L extends Layout = any, U extends User = any, A extends App = any> {
/** Observable stream of settings change notifications */
readonly notify: Observable<SettingsNotify>;
/** Current layout settings */
layout: L;
/** Current application settings */
app: A;
/** Current user settings */
user: U;
/** Update layout settings by name or object */
setLayout(name: string | L, value?: any): boolean;
/** Update application settings */
setApp(value: A): void;
/** Update user settings */
setUser(value: U): void;
/** Get data from localStorage by key */
getData(key: string): any;
/** Set data to localStorage by key */
setData(key: string, value: any): void;
}
interface SettingsNotify {
/** Type of settings that changed */
type: 'layout' | 'app' | 'user';
/** Name of specific setting (for layout changes) */
name?: string;
/** New value */
value: any;
}Usage Examples:
import { Component, inject } from "@angular/core";
import { SettingsService } from "@delon/theme";
// Define custom settings interfaces
interface MyLayout {
collapsed: boolean;
colorWeak: boolean;
theme: 'default' | 'dark' | 'compact';
lang: string;
}
interface MyUser {
name: string;
email: string;
avatar: string;
permissions: string[];
}
interface MyApp {
name: string;
version: string;
description: string;
}
@Component({
selector: "app-settings",
template: `
<div class="settings-panel">
<h3>Theme Settings</h3>
<label>
<input
type="checkbox"
[checked]="settings.layout.collapsed"
(change)="toggleSidebar()"
/>
Collapse Sidebar
</label>
<label>
Theme:
<select
[value]="settings.layout.theme"
(change)="changeTheme($event)"
>
<option value="default">Default</option>
<option value="dark">Dark</option>
<option value="compact">Compact</option>
</select>
</label>
</div>
`
})
export class SettingsComponent {
settings = inject(SettingsService<MyLayout, MyUser, MyApp>);
constructor() {
// Initialize settings
this.settings.setLayout({
collapsed: false,
colorWeak: false,
theme: 'default',
lang: 'en'
});
this.settings.setUser({
name: 'John Doe',
email: 'john@example.com',
avatar: '/assets/avatar.png',
permissions: ['read', 'write']
});
this.settings.setApp({
name: 'My Angular App',
version: '1.0.0',
description: 'Enterprise Angular application'
});
// Listen to settings changes
this.settings.notify.subscribe(change => {
console.log(`Settings changed:`, change);
if (change.type === 'layout' && change.name === 'theme') {
this.applyTheme(change.value);
}
});
}
toggleSidebar() {
this.settings.setLayout('collapsed', !this.settings.layout.collapsed);
}
changeTheme(event: Event) {
const theme = (event.target as HTMLSelectElement).value;
this.settings.setLayout('theme', theme);
}
private applyTheme(theme: string) {
document.body.className = `theme-${theme}`;
}
}Base interfaces for settings data structures with extensible properties.
/**
* Base layout settings interface
* Extend this interface for custom layout properties
*/
interface Layout {
[key: string]: any;
}
/**
* Base user settings interface
* Extend this interface for custom user properties
*/
interface User {
[key: string]: any;
}
/**
* Base application settings interface
* Extend this interface for custom app properties
*/
interface App {
[key: string]: any;
}
/**
* Settings change notification interface
* Provides details about which settings changed
*/
interface SettingsNotify {
/** Type of settings that changed */
type: 'layout' | 'app' | 'user';
/** Name of specific setting (for layout changes) */
name?: string;
/** New value that was set */
value: any;
}Usage Examples:
// Define typed settings interfaces
interface AppLayout extends Layout {
// Navigation
collapsed: boolean;
sidebarWidth: number;
// Appearance
theme: 'light' | 'dark' | 'auto';
colorPrimary: string;
colorWeak: boolean;
// Behavior
fixedHeader: boolean;
fixedSidebar: boolean;
contentWidth: 'fluid' | 'fixed';
// Internationalization
lang: string;
}
interface AppUser extends User {
// Identity
id: string;
name: string;
email: string;
avatar?: string;
// Authorization
roles: string[];
permissions: string[];
// Preferences
timezone: string;
dateFormat: string;
notifications: boolean;
}
interface AppSettings extends App {
// App info
name: string;
version: string;
description: string;
logo: string;
// Features
features: {
analytics: boolean;
notifications: boolean;
darkMode: boolean;
};
// API
apiUrl: string;
timeout: number;
}
// Use typed service
const settingsService = inject(SettingsService<AppLayout, AppUser, AppSettings>);Advanced settings storage and retrieval methods for complex data management.
/**
* Get data from localStorage by key
* Returns parsed JSON data or null if not found
*/
getData(key: string): any;
/**
* Set data to localStorage by key
* Automatically stringifies objects and handles errors
*/
setData(key: string, value: any): void;Usage Examples:
import { SettingsService } from "@delon/theme";
@Component({})
export class SettingsStorageExample {
constructor(private settings: SettingsService) {}
saveUserPreferences() {
// Save complex user preferences
const preferences = {
dashboardLayout: {
widgets: ['weather', 'calendar', 'tasks'],
columns: 3
},
notifications: {
email: true,
push: false,
frequency: 'daily'
},
shortcuts: [
{ key: 'ctrl+d', action: 'dashboard' },
{ key: 'ctrl+u', action: 'users' }
]
};
this.settings.setData('user-preferences', preferences);
}
loadUserPreferences() {
// Load saved preferences
const preferences = this.settings.getData('user-preferences');
if (preferences) {
console.log('Dashboard widgets:', preferences.dashboardLayout.widgets);
console.log('Email notifications:', preferences.notifications.email);
}
}
saveRecentActions() {
// Track recent user actions
const recentActions = this.settings.getData('recent-actions') || [];
recentActions.unshift({
action: 'view-report',
timestamp: new Date().toISOString(),
data: { reportId: '123' }
});
// Keep only last 10 actions
if (recentActions.length > 10) {
recentActions.splice(10);
}
this.settings.setData('recent-actions', recentActions);
}
clearAllData() {
// Clear specific stored data
this.settings.setData('user-preferences', null);
this.settings.setData('recent-actions', null);
}
}Default settings provider for dependency injection configuration.
/**
* Default settings provider
* Provides default configuration for SettingsService
*/
const ALAIN_SETTING_DEFAULT: Provider;Usage Examples:
import { NgModule } from "@angular/core";
import { AlainThemeModule, ALAIN_SETTING_DEFAULT } from "@delon/theme";
// Custom settings provider
const CUSTOM_SETTINGS_PROVIDER: Provider = {
provide: SettingsService,
useFactory: () => {
const service = new SettingsService();
// Initialize with default values
service.setLayout({
collapsed: false,
theme: 'default',
lang: 'en'
});
return service;
}
};
@NgModule({
imports: [AlainThemeModule.forRoot()],
providers: [
// Use default provider
ALAIN_SETTING_DEFAULT,
// Or use custom provider
// CUSTOM_SETTINGS_PROVIDER
]
})
export class AppModule {}