Get started with Dexie in Angular
1. Create an Angular project
Here we refer to Angular’s own Getting Started page.
2. Install dexie
npm install dexie
3. Create a file db.ts
Applications typically have one single Dexie instance declared as its own module. This is where you declare which tables you need and how each table shall be indexed. A Dexie instance is a singleton throughout the application - you do not need to create it on demand. Export the resulting db
instance from your module so that you can use it from your services to write or query data.
To make the best Typescript experience with Dexie.js, table properties (such as db.todoLists
and db.todoItems
) needs to be explicitly declared on a subclass of Dexie just to help out with the typings for your db instance, its tables and entity models.
// db.ts
import Dexie, { Table } from 'dexie';
export interface TodoList {
id?: number;
title: string;
}
export interface TodoItem {
id?: number;
todoListId: number;
title: string;
done?: boolean;
}
export class AppDB extends Dexie {
todoItems!: Table<TodoItem, number>;
todoLists!: Table<TodoList, number>;
constructor() {
super('ngdexieliveQuery');
this.version(3).stores({
todoLists: '++id',
todoItems: '++id, todoListId',
});
this.on('populate', () => this.populate());
}
async populate() {
const todoListId = await db.todoLists.add({
title: 'To Do Today',
});
await db.todoItems.bulkAdd([
{
todoListId,
title: 'Feed the birds',
},
{
todoListId,
title: 'Watch a movie',
},
{
todoListId,
title: 'Have some sleep',
},
]);
}
}
export const db = new AppDB();
4. Turn App into an Offline ToDo app
In this sample we will use two components that builds up our ToDo application. For simplicity, we are letting our components talk directly to the db here. In a real application you might prefer to put the database action and queries via services.
// app.component.ts
import { Component, VERSION } from '@angular/core';
import { liveQuery } from 'dexie';
import { db, TodoList } from '../db';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
todoLists$ = liveQuery(() => db.todoLists.toArray());
listName = 'My new list';
async addNewList() {
await db.todoLists.add({
title: this.listName,
});
}
identifyList(index: number, list: TodoList) {
return `${list.id}${list.title}`;
}
}
<!-- app.component.html -->
<h1>A very simple liveQuery() example</h1>
<div *ngFor="let todoList of todoLists$ | async; trackBy: identifyList">
<itemlist [todoList]="todoList"></itemlist>
</div>
<label>
Add new list:
<input
autocomplete="off"
type="text"
id="name"
#name
[(ngModel)]="listName"
/>
</label>
<button type="submit" (click)="addNewList()">Add new list</button>
5. Add the ItemList component
// itemlist.component.ts
import { Component, ElementRef, Input, ViewChild } from '@angular/core';
import { liveQuery } from 'dexie';
import { db, Item, TodoItem, TodoList } from '../db';
@Component({
selector: 'itemlist',
templateUrl: './itemlist.component.html',
styleUrls: ['./itemlist.component.css'],
})
export class ItemListComponent {
@Input() todoList: TodoList;
// Observe an arbitrary query:
todoItems$ = liveQuery(
() => this.listTodoItems()
);
async listTodoItems() {
return await db.todoItems
.where({
todoListId: this.todoList.id,
})
.toArray();
}
async addItem() {
await db.todoItems.add({
title: this.itemName,
todoListId: this.todoList.id,
});
}
itemName = 'My new item';
}
<!-- itemlist.component.html -->
<h3>{{ todoList.title }}</h3>
<!--
Adding item form
-->
<label>
Add item:
<input
autocomplete="off"
type="text"
id="name"
#name
[(ngModel)]="itemName"
/>
</label>
<button type="submit" (click)="addItem()">Add ToDo</button>
<!--
Rendering todoItems$
-->
<ul>
<li *ngFor="let item of todoItems$ | async">
{{ item.title }}
</li>
</ul>
6. Put it together
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { ItemListComponent } from './itemlist.component';
@NgModule({
imports: [BrowserModule, FormsModule],
declarations: [AppComponent, ItemListComponent],
bootstrap: [AppComponent],
})
export class AppModule {}
Table of Contents
- API Reference
- Access Control in Dexie Cloud
- Add demo users
- Add public data
- Authentication in Dexie Cloud
- Best Practices
- Building Addons
- Collection
- Collection.and()
- Collection.clone()
- Collection.count()
- Collection.delete()
- Collection.desc()
- Collection.distinct()
- Collection.each()
- Collection.eachKey()
- Collection.eachPrimaryKey()
- Collection.eachUniqueKey()
- Collection.filter()
- Collection.first()
- Collection.keys()
- Collection.last()
- Collection.limit()
- Collection.modify()
- Collection.offset()
- Collection.or()
- Collection.primaryKeys()
- Collection.raw()
- Collection.reverse()
- Collection.sortBy()
- Collection.toArray()
- Collection.uniqueKeys()
- Collection.until()
- Compound Index
- Consistency in Dexie Cloud
- Consuming Dexie as a module
- DBCore
- DBCoreAddRequest
- DBCoreCountRequest
- DBCoreCursor
- DBCoreDeleteRangeRequest
- DBCoreDeleteRequest
- DBCoreGetManyRequest
- DBCoreGetRequest
- DBCoreIndex
- DBCoreKeyRange
- DBCoreMutateRequest
- DBCoreMutateResponse
- DBCoreOpenCursorRequest
- DBCorePutRequest
- DBCoreQuery
- DBCoreQueryRequest
- DBCoreQueryResponse
- DBCoreRangeType
- DBCoreSchema
- DBCoreTable
- DBCoreTableSchema
- DBCoreTransaction
- DBCoreTransactionMode
- DBPermissionSet
- Deprecations
- Derived Work
- Design
- Dexie Cloud API
- Dexie Cloud CLI
- Dexie Cloud Docs
- Dexie Cloud REST API
- Dexie Constructor
- Dexie.AbortError
- Dexie.BulkError
- Dexie.ConstraintError
- Dexie.DataCloneError
- Dexie.DataError
- Dexie.DatabaseClosedError
- Dexie.IncompatiblePromiseError
- Dexie.InternalError
- Dexie.InvalidAccessError
- Dexie.InvalidArgumentError
- Dexie.InvalidStateError
- Dexie.InvalidTableError
- Dexie.MissingAPIError
- Dexie.ModifyError
- Dexie.NoSuchDatabaseErrorError
- Dexie.NotFoundError
- Dexie.Observable
- Dexie.Observable.DatabaseChange
- Dexie.OpenFailedError
- Dexie.PrematureCommitError
- Dexie.QuotaExceededError
- Dexie.ReadOnlyError
- Dexie.SchemaError
- Dexie.SubTransactionError
- Dexie.Syncable
- Dexie.Syncable.IDatabaseChange
- Dexie.Syncable.IPersistentContext
- Dexie.Syncable.ISyncProtocol
- Dexie.Syncable.StatusTexts
- Dexie.Syncable.Statuses
- Dexie.Syncable.registerSyncProtocol()
- Dexie.TimeoutError
- Dexie.TransactionInactiveError
- Dexie.UnknownError
- Dexie.UnsupportedError
- Dexie.UpgradeError()
- Dexie.VersionChangeError
- Dexie.VersionError
- Dexie.[table]
- Dexie.addons
- Dexie.async()
- Dexie.backendDB()
- Dexie.close()
- Dexie.currentTransaction
- Dexie.debug
- Dexie.deepClone()
- Dexie.defineClass()
- Dexie.delByKeyPath()
- Dexie.delete()
- Dexie.derive()
- Dexie.events()
- Dexie.exists()
- Dexie.extend()
- Dexie.fakeAutoComplete()
- Dexie.getByKeyPath()
- Dexie.getDatabaseNames()
- Dexie.hasFailed()
- Dexie.ignoreTransaction()
- Dexie.isOpen()
- Dexie.js
- Dexie.name
- Dexie.on()
- Dexie.on.blocked
- Dexie.on.close
- Dexie.on.error
- Dexie.on.populate
- Dexie.on.populate-(old-version)
- Dexie.on.ready
- Dexie.on.storagemutated
- Dexie.on.versionchange
- Dexie.open()
- Dexie.override()
- Dexie.semVer
- Dexie.setByKeyPath()
- Dexie.shallowClone()
- Dexie.spawn()
- Dexie.table()
- Dexie.tables
- Dexie.transaction()
- Dexie.transaction()-(old-version)
- Dexie.use()
- Dexie.verno
- Dexie.version
- Dexie.version()
- Dexie.vip()
- Dexie.waitFor()
- DexieCloudOptions
- DexieError
- Docs Home
- Download
- Export and Import Database
- Get started with Dexie in Angular
- Get started with Dexie in React
- Get started with Dexie in Svelte
- Get started with Dexie in Vue
- Hello World
- How To Use the StorageManager API
- Inbound
- IndexSpec
- Indexable Type
- IndexedDB on Safari
- Invite
- Limits
- Member
- Migrating existing DB to Dexie
- MultiEntry Index
- PersistedSyncState
- Promise
- Promise.PSD
- Promise.catch()
- Promise.finally()
- Promise.on.error
- Promise.onuncatched
- Purchase Subscription
- Questions and Answers
- Realm
- Releasing Dexie
- Road Map
- Road Map: Dexie 4.0
- Road Map: Dexie Cloud
- Role
- Run Dexie Cloud on Own Servers
- Sharding and Scalability
- Simplify with yield
- Stop Putin!
- SyncState
- Table
- Table Schema
- Table.add()
- Table.bulkAdd()
- Table.bulkDelete()
- Table.bulkGet()
- Table.bulkPut()
- Table.bulkUpdate()
- Table.clear()
- Table.count()
- Table.defineClass()
- Table.delete()
- Table.each()
- Table.filter()
- Table.get()
- Table.hook('creating')
- Table.hook('deleting')
- Table.hook('reading')
- Table.hook('updating')
- Table.limit()
- Table.mapToClass()
- Table.name
- Table.offset()
- Table.orderBy()
- Table.put()
- Table.reverse()
- Table.schema
- Table.toArray()
- Table.toCollection()
- Table.update()
- Table.where()
- The main limitations of IndexedDB
- Transaction
- Transaction.abort()
- Transaction.on.abort
- Transaction.on.complete
- Transaction.on.error
- Transaction.table()
- Tutorial
- Typescript
- Understanding the basics
- UserLogin
- Version
- Version.stores()
- Version.upgrade()
- WhereClause
- WhereClause.above()
- WhereClause.aboveOrEqual()
- WhereClause.anyOf()
- WhereClause.anyOfIgnoreCase()
- WhereClause.below()
- WhereClause.belowOrEqual()
- WhereClause.between()
- WhereClause.equals()
- WhereClause.equalsIgnoreCase()
- WhereClause.inAnyRange()
- WhereClause.noneOf()
- WhereClause.notEqual()
- WhereClause.startsWith()
- WhereClause.startsWithAnyOf()
- WhereClause.startsWithAnyOfIgnoreCase()
- WhereClause.startsWithIgnoreCase()
- db.cloud.configure()
- db.cloud.currentUser
- db.cloud.currentUserId
- db.cloud.events.syncComplete
- db.cloud.invites
- db.cloud.login()
- db.cloud.logout()
- db.cloud.options
- db.cloud.permissions()
- db.cloud.persistedSyncState
- db.cloud.roles
- db.cloud.schema
- db.cloud.sync()
- db.cloud.syncState
- db.cloud.userInteraction
- db.cloud.usingServiceWorker
- db.cloud.version
- db.cloud.webSocketStatus
- db.members
- db.realms
- db.roles
- db.syncable.connect()
- db.syncable.delete()
- db.syncable.disconnect()
- db.syncable.getOptions()
- db.syncable.getStatus()
- db.syncable.list()
- db.syncable.on('statusChanged')
- db.syncable.setFilter()
- dexie-cloud-addon
- dexie-react-hooks
- liveQuery()
- unhandledrejection-event
- useLiveQuery()
- useObservable()
- usePermissions()