diff --git a/files/en-us/web/api/idbdatabase/index.md b/files/en-us/web/api/idbdatabase/index.md index 2d203f8d8cb7aa6..491245d2d8dcdc7 100644 --- a/files/en-us/web/api/idbdatabase/index.md +++ b/files/en-us/web/api/idbdatabase/index.md @@ -44,7 +44,7 @@ Listen to these events using `addEventListener()` or by assigning an event liste - : An event fired when the database connection is unexpectedly closed. - [`versionchange`](/en-US/docs/Web/API/IDBDatabase/versionchange_event) - - : An event fired when a database structure change was requested. + - : An event fired when another connection requested a structure change (an upgrade) or a deletion. Handler code should [close the database](/en-US/docs/Web/API/IDBDatabase/versionchange_event) so that the change is not blocked. The following events are available to `IDBDatabase` via event bubbling from {{domxref("IDBTransaction")}}: diff --git a/files/en-us/web/api/idbdatabase/versionchange_event/index.md b/files/en-us/web/api/idbdatabase/versionchange_event/index.md index b97b1f69291e19c..32d32e870e7190e 100644 --- a/files/en-us/web/api/idbdatabase/versionchange_event/index.md +++ b/files/en-us/web/api/idbdatabase/versionchange_event/index.md @@ -8,8 +8,11 @@ browser-compat: api.IDBDatabase.versionchange_event {{APIRef("IndexedDB")}} -The `versionchange` event is fired when a database structure change ([`upgradeneeded`](/en-US/docs/Web/API/IDBOpenDBRequest/upgradeneeded_event) event send on an [`IDBOpenDBRequest`](/en-US/docs/Web/API/IDBOpenDBRequest) or [`IDBFactory.deleteDatabase`](/en-US/docs/Web/API/IDBFactory/deleteDatabase)) was requested elsewhere (most probably in -another window/tab on the same computer). +The `versionchange` event is fired when a database structure change ([`upgradeneeded`](/en-US/docs/Web/API/IDBOpenDBRequest/upgradeneeded_event) event sent on an [`IDBOpenDBRequest`](/en-US/docs/Web/API/IDBOpenDBRequest)) or a deletion ([`IDBFactory.deleteDatabase`](/en-US/docs/Web/API/IDBFactory/deleteDatabase)) was requested from another connection — most probably another window or tab of the same page on the same computer. + +An upgrade or deletion cannot proceed while other connections to the database are open: it waits until every other connection has been closed. Handling `versionchange` by calling {{domxref("IDBDatabase.close()")}} is the usual way to let it proceed; if the connection stays open, the request in the other tab stays pending until the connection is closed, for example when the user closes the tab. + +If connections are still open after the `versionchange` events have been dispatched, the request that asked for the change receives a [`blocked`](/en-US/docs/Web/API/IDBOpenDBRequest/blocked_event) event. Once the remaining connections are closed, an upgrade continues with that request's [`upgradeneeded`](/en-US/docs/Web/API/IDBOpenDBRequest/upgradeneeded_event) event. Code that keeps running after closing its connection should also expect that reopening the database with its old version number now fails with a `VersionError`, because the requested version is lower than the database's current version. ## Syntax @@ -27,64 +30,49 @@ A generic {{domxref("Event")}}. ## Examples -This example opens a database and, on success, adds a listener to `versionchange`: +The important thing a `versionchange` handler can do is close the database, so that the tab that asked for the change is unblocked. A common pattern is to close the connection and tell the user to reload: ```js -// Open the database -const dBOpenRequest = window.indexedDB.open("Nonexistent", 4); +const dbOpenRequest = window.indexedDB.open("toDoList", 1); -dBOpenRequest.onupgradeneeded = (event) => { +dbOpenRequest.onsuccess = (event) => { const db = event.target.result; - // Create an objectStore for this database - const objectStore = db.createObjectStore("toDoList", { - keyPath: "taskTitle", - }); - - // define what data items the objectStore will contain - objectStore.createIndex("hours", "hours", { unique: false }); - objectStore.createIndex("minutes", "minutes", { unique: false }); - objectStore.createIndex("day", "day", { unique: false }); - objectStore.createIndex("month", "month", { unique: false }); - objectStore.createIndex("year", "year", { unique: false }); -}; -dBOpenRequest.addEventListener("success", (event) => { - const db = event.target.result; - db.addEventListener("versionchange", (event) => { - console.log("The version of this database has changed"); - }); -}); + db.onversionchange = () => { + // Another tab asked for a newer version. Close our connection so the + // other tab's upgradeneeded can run, then ask the user to reload. + db.close(); + document.querySelector("p").textContent = + "A new version of this page is ready. Please reload or close this tab."; + }; +}; ``` -The same example, using the `onversionchange` event handler property: +A tab that requests the change should show the state of the request to the user, so that a block on another tab is not mistaken for a failure: ```js -// Open the database -const dBOpenRequest = window.indexedDB.open("Nonexistent", 4); +const dbOpenRequest = window.indexedDB.open("toDoList", 2); + +// Another tab still has the database open (it did not close its connection +// in response to versionchange), so the upgrade has to wait. +dbOpenRequest.onblocked = () => { + document.querySelector("p").textContent = + "Still waiting for other tabs to close the database."; +}; -dBOpenRequest.onupgradeneeded = (event) => { +dbOpenRequest.onupgradeneeded = (event) => { const db = event.target.result; - // Create an objectStore for this database - const objectStore = db.createObjectStore("toDoList", { - keyPath: "taskTitle", - }); - - // define what data items the objectStore will contain - objectStore.createIndex("hours", "hours", { unique: false }); - objectStore.createIndex("minutes", "minutes", { unique: false }); - objectStore.createIndex("day", "day", { unique: false }); - objectStore.createIndex("month", "month", { unique: false }); - objectStore.createIndex("year", "year", { unique: false }); + db.createObjectStore("toDoList", { keyPath: "taskTitle" }); }; -dBOpenRequest.onsuccess = (event) => { +dbOpenRequest.onsuccess = (event) => { const db = event.target.result; - db.onversionchange = (event) => { - console.log("The version of this database has changed"); - }; + document.querySelector("p").textContent = "Version " + db.version; }; ``` +See also [Version changes while a web app is open in another tab](/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB#version_changes_while_a_web_app_is_open_in_another_tab) in the Using IndexedDB guide. + ## Specifications {{Specifications}}