Skip to main content
current (v22)

Advanced Features

tip
import { CatbeeCookieService, CatbeeSsrCookieService } from '@ng-catbee/cookie';

Use CatbeeCookieService in browser contexts and CatbeeSsrCookieService for server-side rendering (SSR) scenarios.

warning

CatbeeSsrCookieService provides only getting cookies from the request headers and does not support setting cookies.

Partial JSON Updates​

UpdateJson Method​

The updateJson method allows you to update specific properties of a JSON cookie without replacing the entire object.

import { Component, inject } from '@angular/core';
import { CatbeeCookieService } from '@ng-catbee/cookie';

interface AppSettings {
theme: string;
language: string;
notifications: boolean;
sidebar: boolean;
fontSize: number;
autoSave: boolean;
}

@Component({
selector: 'app-settings-manager',
standalone: true,
template: `
<div class="settings">
<h2>Application Settings</h2>

<div class="setting-group">
<h3>Appearance</h3>
<button (click)="toggleTheme()">Toggle Theme</button>
<button (click)="increaseFontSize()">Increase Font Size</button>
</div>

<div class="setting-group">
<h3>Behavior</h3>
<button (click)="toggleNotifications()">
{{ settings.notifications ? 'Disable' : 'Enable' }} Notifications
</button>
<button (click)="toggleAutoSave()">
{{ settings.autoSave ? 'Disable' : 'Enable' }} Auto-Save
</button>
</div>

<button (click)="resetSettings()">Reset to Defaults</button>
</div>
`
})
export class SettingsManagerComponent {
private cookieService = inject(CatbeeCookieService);

readonly defaultSettings: AppSettings = {
theme: 'light',
language: 'en',
notifications: true,
sidebar: true,
fontSize: 14,
autoSave: true
};

settings: AppSettings = { ...this.defaultSettings };

ngOnInit() {
this.settings = this.cookieService.getJsonWithDefault(
'appSettings',
this.defaultSettings,
{ expires: 365 }
);
}

toggleTheme() {
const newTheme = this.settings.theme === 'light' ? 'dark' : 'light';

// Update only the theme property
this.cookieService.updateJson(
'appSettings',
{ theme: newTheme },
this.defaultSettings
);

this.settings.theme = newTheme;
}

toggleNotifications() {
const newValue = !this.settings.notifications;

this.cookieService.updateJson(
'appSettings',
{ notifications: newValue },
this.defaultSettings
);

this.settings.notifications = newValue;
}

increaseFontSize() {
const newSize = this.settings.fontSize + 2;

this.cookieService.updateJson(
'appSettings',
{ fontSize: newSize },
this.defaultSettings
);

this.settings.fontSize = newSize;
}

toggleAutoSave() {
const newValue = !this.settings.autoSave;

this.cookieService.updateJson(
'appSettings',
{ autoSave: newValue },
this.defaultSettings
);

this.settings.autoSave = newValue;
}

updateMultipleSettings() {
// Update multiple properties at once
this.cookieService.updateJson(
'appSettings',
{
theme: 'dark',
fontSize: 16,
sidebar: false
},
this.defaultSettings
);
}

resetSettings() {
this.cookieService.setJson('appSettings', this.defaultSettings, {
expires: 365
});
this.settings = { ...this.defaultSettings };
}
}

User Profile Updates​

import { Component, inject } from '@angular/core';
import { CatbeeCookieService } from '@ng-catbee/cookie';

interface UserProfile {
name: string;
email: string;
avatar: string;
bio: string;
location: string;
website: string;
}

@Component({
selector: 'app-profile-editor',
standalone: true,
template: `
<form (ngSubmit)="saveProfile()">
<input [(ngModel)]="profile.name" name="name" placeholder="Name" />
<input [(ngModel)]="profile.email" name="email" placeholder="Email" />
<textarea [(ngModel)]="profile.bio" name="bio" placeholder="Bio"></textarea>
<input [(ngModel)]="profile.location" name="location" placeholder="Location" />

<button type="submit">Save Profile</button>
</form>
`
})
export class ProfileEditorComponent {
private cookieService = inject(CatbeeCookieService);

readonly defaultProfile: UserProfile = {
name: '',
email: '',
avatar: '',
bio: '',
location: '',
website: ''
};

profile: UserProfile = { ...this.defaultProfile };

ngOnInit() {
this.profile = this.cookieService.getJsonWithDefault(
'userProfile',
this.defaultProfile,
{ expires: 90 }
);
}

saveProfile() {
// Update all modified fields
this.cookieService.updateJson(
'userProfile',
this.profile,
this.defaultProfile,
{ expires: 90 }
);
}

updateAvatar(avatarUrl: string) {
// Update only the avatar
this.cookieService.updateJson(
'userProfile',
{ avatar: avatarUrl },
this.defaultProfile
);
this.profile.avatar = avatarUrl;
}
}

Bulk Operations​

Deleting Multiple Cookies​

import { Component, inject } from '@angular/core';
import { CatbeeCookieService } from '@ng-catbee/cookie';

@Component({
selector: 'app-session-manager',
standalone: true,
template: `
<div class="session-manager">
<h2>Session Management</h2>

<button (click)="logout()">Logout</button>
<button (click)="clearUserData()">Clear User Data</button>
<button (click)="clearAnalytics()">Clear Analytics</button>
<button (click)="clearEverything()">Clear All Cookies</button>
</div>
`
})
export class SessionManagerComponent {
private cookieService = inject(CatbeeCookieService);

logout() {
// Clear authentication-related cookies
this.cookieService.deleteMany([
'authToken',
'refreshToken',
'sessionId',
'userId'
]);
}

clearUserData() {
// Clear user preferences and data
this.cookieService.deleteMany([
'userPrefs',
'userProfile',
'recentSearches',
'shoppingCart',
'wishlist'
]);
}

clearAnalytics() {
// Clear analytics cookies
this.cookieService.deleteMany([
'pageViews',
'visitCount',
'lastVisit',
'sessionStart'
]);
}

clearEverything() {
// Delete all accessible cookies
this.cookieService.deleteAll();
}

clearCookiesWithPath() {
// Delete all cookies for a specific path
this.cookieService.deleteAll({ path: '/' });
}
}

Setting Multiple Cookies​

import { Component, inject } from '@angular/core';
import { CatbeeCookieService } from '@ng-catbee/cookie';

interface SessionData {
userId: string;
sessionId: string;
loginTime: string;
expiresAt: string;
}

@Component({
selector: 'app-session-initializer',
standalone: true,
template: `...`
})
export class SessionInitializerComponent {
private cookieService = inject(CatbeeCookieService);

initializeSession(sessionData: SessionData) {
const options = {
expires: 1, // 1 day
secure: true,
sameSite: 'Strict' as const
};

// Set multiple cookies for session
this.cookieService.set('userId', sessionData.userId, options);
this.cookieService.set('sessionId', sessionData.sessionId, options);
this.cookieService.set('loginTime', sessionData.loginTime, options);
this.cookieService.set('expiresAt', sessionData.expiresAt, options);

// Or use a helper method
this.setMultipleCookies({
'userId': sessionData.userId,
'sessionId': sessionData.sessionId,
'loginTime': sessionData.loginTime,
'expiresAt': sessionData.expiresAt
}, options);
}

private setMultipleCookies(
cookies: Record<string, string>,
options: any
) {
Object.entries(cookies).forEach(([name, value]) => {
this.cookieService.set(name, value, options);
});
}
}
import { Component, inject, OnInit } from '@angular/core';
import { CatbeeCookieService } from '@ng-catbee/cookie';

interface CookieInfo {
name: string;
value: string;
size: number;
}

@Component({
selector: 'app-cookie-inspector',
standalone: true,
template: `
<div class="cookie-inspector">
<h2>Cookie Inspector</h2>

<div class="stats">
<p>Total Cookies: {{ totalCookies }}</p>
<p>Total Size: {{ totalSize }} bytes</p>
</div>

<table>
<thead>
<tr>
<th>Name</th>
<th>Value</th>
<th>Size</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@for (cookie of cookieList; track cookie.name) {
<tr>
<td>{{ cookie.name }}</td>
<td class="value">{{ cookie.value }}</td>
<td>{{ cookie.size }} bytes</td>
<td>
<button (click)="deleteCookie(cookie.name)">Delete</button>
<button (click)="viewDetails(cookie)">Details</button>
</td>
</tr>
}
</tbody>
</table>

<button (click)="refresh()">Refresh</button>
<button (click)="exportCookies()">Export</button>
</div>
`
})
export class CookieInspectorComponent implements OnInit {
private cookieService = inject(CatbeeCookieService);

cookieList: CookieInfo[] = [];
totalCookies = 0;
totalSize = 0;

ngOnInit() {
this.refresh();
}

refresh() {
const entries = this.cookieService.entries();

this.cookieList = entries.map(([name, value]) => ({
name,
value,
size: this.calculateSize(name, value)
}));

this.totalCookies = this.cookieList.length;
this.totalSize = this.cookieList.reduce((sum, cookie) => sum + cookie.size, 0);
}

private calculateSize(name: string, value: string): number {
// Cookie size = name + value + overhead
return new Blob([`${name}=${value}`]).size;
}

deleteCookie(name: string) {
this.cookieService.delete(name);
this.refresh();
}

viewDetails(cookie: CookieInfo) {
console.log('Cookie Details:', {
name: cookie.name,
value: cookie.value,
size: cookie.size,
// Try to parse as JSON
parsed: this.tryParseJson(cookie.value)
});
}

private tryParseJson(value: string): any {
try {
return JSON.parse(value);
} catch {
return value;
}
}

exportCookies() {
const data = this.cookieService.getAll();
const json = JSON.stringify(data, null, 2);

// Download as JSON file
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `cookies-${Date.now()}.json`;
a.click();
URL.revokeObjectURL(url);
}
}
import { Component, inject, OnInit, OnDestroy } from '@angular/core';
import { CatbeeCookieService } from '@ng-catbee/cookie';
import { BehaviorSubject, interval, Subscription } from 'rxjs';

@Component({
selector: 'app-cookie-watcher',
standalone: true,
template: `
<div class="watcher">
<h2>Cookie Watcher</h2>

<p>Username: {{ username$ | async }}</p>
<p>Theme: {{ theme$ | async }}</p>

<button (click)="updateUsername()">Update Username</button>
<button (click)="updateTheme()">Toggle Theme</button>
</div>
`
})
export class CookieWatcherComponent implements OnInit, OnDestroy {
private cookieService = inject(CatbeeCookieService);

username$ = new BehaviorSubject<string>('');
theme$ = new BehaviorSubject<string>('light');

private subscription?: Subscription;

ngOnInit() {
// Initial values
this.username$.next(this.cookieService.get('username') || 'Guest');
this.theme$.next(this.cookieService.get('theme') || 'light');

// Poll for changes every second
this.subscription = interval(1000).subscribe(() => {
this.checkForChanges();
});
}

ngOnDestroy() {
this.subscription?.unsubscribe();
}

private checkForChanges() {
const currentUsername = this.cookieService.get('username') || 'Guest';
const currentTheme = this.cookieService.get('theme') || 'light';

if (currentUsername !== this.username$.value) {
this.username$.next(currentUsername);
}

if (currentTheme !== this.theme$.value) {
this.theme$.next(currentTheme);
}
}

updateUsername() {
const names = ['Alice', 'Bob', 'Charlie', 'Diana'];
const randomName = names[Math.floor(Math.random() * names.length)];
this.cookieService.set('username', randomName);
}

updateTheme() {
const currentTheme = this.theme$.value;
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
this.cookieService.set('theme', newTheme);
}
}

Cross-Tab Synchronization​

import { Component, inject, OnInit, OnDestroy } from '@angular/core';
import { CatbeeCookieService } from '@ng-catbee/cookie';
import { fromEvent, Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';

@Component({
selector: 'app-sync-manager',
standalone: true,
template: `
<div class="sync-manager">
<h2>Cross-Tab Cookie Sync</h2>

<p>Shared Counter: {{ counter }}</p>
<button (click)="increment()">Increment</button>

<p>Theme: {{ theme }}</p>
<button (click)="toggleTheme()">Toggle Theme</button>

<p class="info">
Changes are synced across all open tabs!
</p>
</div>
`
})
export class SyncManagerComponent implements OnInit, OnDestroy {
private cookieService = inject(CatbeeCookieService);

counter = 0;
theme = 'light';

private storageSubscription?: Subscription;

ngOnInit() {
this.loadValues();
this.watchForChanges();
}

ngOnDestroy() {
this.storageSubscription?.unsubscribe();
}

private loadValues() {
this.counter = this.cookieService.getNumberWithDefault('syncCounter', 0);
this.theme = this.cookieService.getWithDefault('syncTheme', 'light');
}

private watchForChanges() {
// Listen for storage events (fired in other tabs)
this.storageSubscription = fromEvent<StorageEvent>(window, 'storage')
.pipe(
filter(event => event.key === 'cookie-sync')
)
.subscribe(() => {
this.loadValues();
});
}

increment() {
this.counter++;
this.cookieService.set('syncCounter', this.counter.toString());
this.broadcastChange();
}

toggleTheme() {
this.theme = this.theme === 'light' ? 'dark' : 'light';
this.cookieService.set('syncTheme', this.theme);
this.broadcastChange();
}

private broadcastChange() {
// Trigger storage event for other tabs
localStorage.setItem('cookie-sync', Date.now().toString());
localStorage.removeItem('cookie-sync');
}
}

Input Validation​

import { Component, inject } from '@angular/core';
import { CatbeeCookieService } from '@ng-catbee/cookie';

@Component({
selector: 'app-validated-input',
standalone: true,
template: `
<form (ngSubmit)="saveSettings()">
<input [(ngModel)]="username" name="username"
placeholder="Username (3-20 chars)" />

<input type="number" [(ngModel)]="age" name="age"
placeholder="Age (1-120)" />

<select [(ngModel)]="country" name="country">
@for (c of allowedCountries; track c) {
<option [value]="c">{{ c }}</option>
}
</select>

<button type="submit">Save</button>

@if (errorMessage) {
<p class="error">{{ errorMessage }}</p>
}
</form>
`
})
export class ValidatedInputComponent {
private cookieService = inject(CatbeeCookieService);

username = '';
age = 0;
country = '';
errorMessage = '';

readonly allowedCountries = ['USA', 'UK', 'Canada', 'Australia'];

ngOnInit() {
this.loadSettings();
}

loadSettings() {
this.username = this.cookieService.get('username') || '';
this.age = this.cookieService.getNumber('age');
this.country = this.cookieService.getEnumWithDefault(
'country',
'USA',
this.allowedCountries
);
}

saveSettings() {
this.errorMessage = '';

// Validate username
if (!this.validateUsername(this.username)) {
this.errorMessage = 'Username must be 3-20 characters';
return;
}

// Validate age
if (!this.validateAge(this.age)) {
this.errorMessage = 'Age must be between 1 and 120';
return;
}

// Validate country
if (!this.allowedCountries.includes(this.country)) {
this.errorMessage = 'Invalid country selected';
return;
}

// Sanitize and save
this.cookieService.set('username', this.sanitizeString(this.username), {
expires: 365
});
this.cookieService.set('age', this.age.toString(), {
expires: 365
});
this.cookieService.set('country', this.country, {
expires: 365
});
}

private validateUsername(username: string): boolean {
return username.length >= 3 && username.length <= 20;
}

private validateAge(age: number): boolean {
return age >= 1 && age <= 120;
}

private sanitizeString(input: string): string {
// Remove special characters that could cause issues
return input.replace(/[^\w\s-]/g, '').trim();
}
}

Migration and Versioning​

import { Component, inject, OnInit } from '@angular/core';
import { CatbeeCookieService } from '@ng-catbee/cookie';

interface UserPreferencesV1 {
theme: string;
language: string;
}

interface UserPreferencesV2 {
theme: string;
language: string;
fontSize: number;
notifications: boolean;
}

@Component({
selector: 'app-preferences-migrator',
standalone: true,
template: `...`
})
export class PreferencesMigratorComponent implements OnInit {
private cookieService = inject(CatbeeCookieService);

ngOnInit() {
this.migratePreferences();
}

private migratePreferences() {
const version = this.cookieService.getNumber('prefsVersion');

if (isNaN(version) || version < 2) {
// Load old format
const oldPrefs = this.cookieService.getJson<UserPreferencesV1>('userPrefs');

if (oldPrefs) {
// Migrate to new format
const newPrefs: UserPreferencesV2 = {
theme: oldPrefs.theme,
language: oldPrefs.language,
fontSize: 14, // New default
notifications: true // New default
};

// Save in new format
this.cookieService.setJson('userPrefs', newPrefs, { expires: 365 });
this.cookieService.set('prefsVersion', '2');

console.log('Migrated preferences to v2');
}
}
}
}

Next Steps​