Angular 20+ module for IndexedDB with a signal-based API. This library provides a reactive, zoneless approach to managing IndexedDB operations using Angular Signals.
- π Signal-based API - Uses Angular Signals, Effects, and Computed properties instead of EventEmitters
- π Reactive Store -
IndexedDBSignalStorefor automatic synchronization between IndexedDB and signals - π― Zoneless - Works without Zone.js
- π SSR Support - Includes state serialization and restoration for server-side rendering
- β Type-safe - Full TypeScript support
- π§ͺ Well-tested - Comprehensive unit and E2E tests
pnpm add ng-indexeddb-signals
# or
npm install ng-indexeddb-signals
# or
yarn add ng-indexeddb-signals@angular/core:^20.0.0tslib:^2.8.1
import { ApplicationConfig } from '@angular/core';
import { provideIndexedDB } from 'ng-indexeddb-signals';
export const appConfig: ApplicationConfig = {
providers: [
provideIndexedDB({
name: 'my-database',
version: 1,
stores: [
{
name: 'users',
keyPath: 'id',
autoIncrement: true,
},
],
}),
],
};Then in main.ts:
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { appConfig } from './app.config';
bootstrapApplication(AppComponent, appConfig);If you prefer to initialize manually, you can still use the service directly:
import { Component, inject, OnInit } from '@angular/core';
import { IndexedDBService } from 'ng-indexeddb-signals';
@Component({
selector: 'app-root',
standalone: true,
// ...
})
export class AppComponent implements OnInit {
private indexedDB = inject(IndexedDBService);
async ngOnInit() {
await this.indexedDB.initialize({
name: 'my-database',
version: 1,
stores: [
{
name: 'users',
keyPath: 'id',
autoIncrement: true,
},
],
});
}
}import { IndexedDBSignalStore } from 'ng-indexeddb-signals';
export class UserService {
private userStore = inject(IndexedDBSignalStore<User>);
constructor() {
// Initialize with store name
this.userStore = new IndexedDBSignalStore<User>('users');
}
// Access reactive data
users = this.userStore.data;
userCount = this.userStore.count;
isLoading = this.userStore.loading;
async loadUsers() {
await this.userStore.refresh();
}
async addUser(user: User) {
await this.userStore.put(user);
}
async deleteUser(id: number) {
await this.userStore.delete(id);
}
}<div>
<p>Users: {{ userService.userCount() }}</p>
<p *ngIf="userService.isLoading()">Loading...</p>
<ul>
<li *ngFor="let user of userService.users()">{{ user.name }}</li>
</ul>
</div>initialize(config: IndexedDBConfig): Promise<void>- Initialize the databaseget<T>(storeName: string, key: IDBValidKey): Promise<T | undefined>- Get a valuegetAll<T>(storeName: string, options?: GetAllOptions): Promise<T[]>- Get all valuesput<T>(storeName: string, value: T, key?: IDBValidKey): Promise<IDBValidKey>- Put a valuedelete(storeName: string, key: IDBValidKey): Promise<void>- Delete a valueclear(storeName: string): Promise<void>- Clear all valuescount(storeName: string, range?: IDBKeyRange): Promise<number>- Count records
connectionState(): ConnectionState- Current connection state ('connecting' | 'open' | 'closed' | 'error')error(): Error | null- Current error, if anyisConnected(): boolean- Whether the database is connectedisConnecting(): boolean- Whether the database is connecting
refresh(): Promise<void>- Refresh data from IndexedDBput(value: T): Promise<IDBValidKey>- Add or update a valuedelete(key: IDBValidKey): Promise<void>- Delete a valueclear(): Promise<void>- Clear all valuescreateFilteredSignal(filterFn: (item: T) => boolean): Signal<T[]>- Create a filtered signal
data(): T[]- All data in the storecount(): number- Number of itemsloading(): boolean- Whether data is loadingisEmpty(): boolean- Whether the store is empty
For server-side rendering, you can serialize and restore IndexedDB state:
// On server
const state = await indexedDBService.serializeState();
// Send to client
// On client (after hydration)
await indexedDBService.restoreState(state);- Node.js 20.x
- pnpm 8+
pnpm install# Run unit tests
pnpm test
# Run unit tests in watch mode
pnpm test:watch
# Run E2E tests
pnpm e2e
# Run linter
pnpm lint
# Fix linting issues
pnpm lint:fix
# Format code
pnpm format
# Build library
pnpm build
# Clean generated files
pnpm cleanThis project uses:
- Vitest for unit testing
- Playwright for E2E testing
All tests must pass before pushing (enforced by Husky hooks).
MIT License - see LICENSE file for details.
Contributions are welcome! Please ensure:
- All tests pass
- Code follows the linting rules
- Commits follow the conventional commit format
- Linear commit history is maintained