| OLD | NEW |
| 1 --- | 1 --- |
| 2 layout: default | 2 layout: default |
| 3 title: "Use IndexedDB" | 3 title: "Use IndexedDB" |
| 4 description: "Use IndexedDB for persistence and offline capability for your app.
" | 4 description: "Use IndexedDB for persistence and offline capability for your app.
" |
| 5 has-permalinks: true | 5 has-permalinks: true |
| 6 tutorial: | 6 tutorial: |
| 7 id: indexeddb | 7 id: indexeddb |
| 8 next: | 8 next: |
| 9 next-title: "A Game of Darts" | 9 next-title: "Home" |
| 10 prev: forms/ | 10 prev: forms/ |
| 11 prev-title: "Get Input from a Form" | 11 prev-title: "Get Input from a Form" |
| 12 --- | 12 --- |
| 13 | 13 |
| 14 {% capture whats_the_point %} | 14 {% capture whats_the_point %} |
| 15 | 15 |
| 16 * IndexedDB is a new standard for client-side storage in modern web browsers. | 16 * IndexedDB is a new standard for client-side storage in modern web browsers. |
| 17 * Client-side storage provides persistence, offline capability, | 17 * Client-side storage provides persistence, offline capability, |
| 18 and other advantages. | 18 and other advantages. |
| 19 * IndexedDB lets you store significant amounts of structured data. | 19 * IndexedDB lets you store significant amounts of structured data. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 such as images, arrays, maps, and objects using IndexedDB. | 56 such as images, arrays, maps, and objects using IndexedDB. |
| 57 The standard does not specify size limits for | 57 The standard does not specify size limits for |
| 58 individual data items or for the database itself, | 58 individual data items or for the database itself, |
| 59 but browsers may impose storage limits. | 59 but browsers may impose storage limits. |
| 60 | 60 |
| 61 IndexedDB provides several advantages. | 61 IndexedDB provides several advantages. |
| 62 Your apps | 62 Your apps |
| 63 | 63 |
| 64 * can have full functionality even if a network connection is not available. | 64 * can have full functionality even if a network connection is not available. |
| 65 * can cache data and restore state between invocations. | 65 * can cache data and restore state between invocations. |
| 66 * won't lose data if the network connected is interrupted. | 66 * won't lose data if the network connection is interrupted. |
| 67 * generate less network traffic. | 67 * generate less network traffic. |
| 68 * perform better because data management happens on the local computer | 68 * perform better because data management happens on the local computer |
| 69 rather than over the Internet. | 69 rather than over the Internet. |
| 70 | 70 |
| 71 <aside class="alert" markdown="1"> | 71 <aside class="alert alert-info" markdown="1"> |
| 72 <strong>Note:</strong> | 72 <strong>Note:</strong> |
| 73 Some browsers don't yet support IndexedDB. | 73 Some browsers don't yet support IndexedDB. |
| 74 Check | 74 Check |
| 75 <a href="http://caniuse.com/#feat=indexeddb" | 75 <a href="http://caniuse.com/#feat=indexeddb" |
| 76 target="_blank">caniuse.com</a> | 76 target="_blank">caniuse.com</a> |
| 77 for up-to-date information. | 77 for up-to-date information. |
| 78 Your app can check programmatically | 78 Your app can check programmatically |
| 79 if the current platform supports IndexedDB | 79 if the current platform supports IndexedDB |
| 80 and adjust accordingly. | 80 and adjust accordingly. |
| 81 </aside> | 81 </aside> |
| (...skipping 10 matching lines...) Expand all Loading... |
| 92 * [Checking for IndexedDB support](#checking-indexeddb) | 92 * [Checking for IndexedDB support](#checking-indexeddb) |
| 93 * [Creating and opening a database](#opening-indexeddb) | 93 * [Creating and opening a database](#opening-indexeddb) |
| 94 * [Creating an object store](#creating-object-store) | 94 * [Creating an object store](#creating-object-store) |
| 95 * [Using a name index](#using-a-name-index) | 95 * [Using a name index](#using-a-name-index) |
| 96 * [Using transactions](#using-transactions) | 96 * [Using transactions](#using-transactions) |
| 97 * [Adding data](#adding-data) | 97 * [Adding data](#adding-data) |
| 98 * [Removing data](#removing-data) | 98 * [Removing data](#removing-data) |
| 99 * [Clearing all data](#clearing-all-data) | 99 * [Clearing all data](#clearing-all-data) |
| 100 * [Using a cursor to get all the records](#getting-data) | 100 * [Using a cursor to get all the records](#getting-data) |
| 101 * [Other resources](#other-resources) | 101 * [Other resources](#other-resources) |
| 102 * [What next?](#what-next) |
| 102 | 103 |
| 103 ##Run the app {#run-the-app} | 104 ##Run the app {#run-the-app} |
| 104 | 105 |
| 105 The `count_down` app below maintains a list of milestones | 106 The `count_down` app below maintains a list of milestones |
| 106 and displays a countdown timer for each one. | 107 and displays a countdown timer for each one. |
| 107 | 108 |
| 108 **Try it!** | 109 **Try it!** |
| 109 Enter the name, date, and time of a milestone—your | 110 Enter the name, date, and time of a milestone—your |
| 110 birthday, for example—and click the plus (**+**) button. | 111 birthday, for example—and click the plus (**+**) button. |
| 111 The app shows the milestone name briefly, | 112 The app starts a countdown timer |
| 112 starts a countdown timer, | 113 and displays the amount of time remaining until the milestone occurs. |
| 113 and then displays the amount of time remaining until the milestone occurs. | |
| 114 The app updates the display every second. | 114 The app updates the display every second. |
| 115 | 115 |
| 116 Close this browser window and reload | 116 Close this browser window and reload |
| 117 <a href="index.html#run-the-app">this page</a>. | 117 <a href="index.html#run-the-app">this page</a>. |
| 118 The milestone you created still exists | 118 The milestone you created still exists |
| 119 because the app stored it in an IndexedDB in the browser. | 119 because the app stored it in an IndexedDB in the browser. |
| 120 | 120 |
| 121 Use the minus (**-**) button to the right of a milestone | 121 Use the minus (**-**) button to the right of a milestone |
| 122 to delete that milestone. | 122 to delete that milestone. |
| 123 Use the **Clear** button to delete all the milestones. | 123 Use the **Clear** button to delete all the milestones. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 151 ##About the app: The basics {#the-basics} | 151 ##About the app: The basics {#the-basics} |
| 152 | 152 |
| 153 The count_down app uses a Model, View, View-model (MVVM) structure. | 153 The count_down app uses a Model, View, View-model (MVVM) structure. |
| 154 | 154 |
| 155  | 155  |
| 156 | 156 |
| 157 * The **View-model**, in the center of the diagram, | 157 * The **View-model**, in the center of the diagram, |
| 158 connects the View and the Model, | 158 connects the View and the Model, |
| 159 using UI and Timer events | 159 using UI and Timer events |
| 160 to make changes to the Model. | 160 to make changes to the Model. |
| 161 The MilestoneApp class is primary class | 161 The MilestoneApp class is the primary class |
| 162 that implements the View-Model—it | 162 that implements the View-Model—it |
| 163 manages the timer, | 163 manages the timer, |
| 164 and implements the app's business logic, | 164 and implements the app's business logic, |
| 165 which manages the information exchange between the Model and the View. | 165 which manages the information exchange between the Model and the View. |
| 166 | 166 |
| 167 * The **View** provides the user interface for the app. | 167 * The **View** provides the user interface for the app. |
| 168 Two custom components implement the View in the count_down app: | 168 Two custom elements implement the View in the count_down app: |
| 169 CountDownComponent describes the user interface for the app as a whole, | 169 CountDownComponent describes the user interface for the app as a whole, |
| 170 and MilestoneComponent describes the UI for an individual milestone. | 170 and MilestoneComponent describes the UI for an individual milestone. |
| 171 These components inform the View-model of UI events. | 171 These components inform the View-model of UI events. |
| 172 | 172 |
| 173 * The **Model** contains and manages the data. | 173 * The **Model** contains and manages the data. |
| 174 The Model, | 174 The Model, |
| 175 implemented by the MilestoneStore class, | 175 implemented by the MilestoneStore class, |
| 176 manages a list of Milestone objects in memory | 176 manages a list of Milestone objects in memory |
| 177 and keeps an IndexedDB in sync with the list, | 177 and keeps an IndexedDB in sync with the list, |
| 178 saving the milestone data persistently. | 178 saving the milestone data persistently. |
| 179 The View-model queries the Model upon initialization | 179 The View-model queries the Model upon initialization |
| 180 and uses Polymer data-bindings to keep the View in sync. | 180 and uses Polymer data-bindings to keep the View in sync. |
| 181 Also, it uses Timer events to trigger updates in the Model. | 181 Also, it uses Timer events to trigger updates in the Model. |
| 182 | 182 |
| 183 ###The libraries used by the count_down app | 183 ###The libraries used by the count_down app |
| 184 | 184 |
| 185 The count_down app uses the following libraries: | 185 The count_down app uses the following libraries: |
| 186 | 186 |
| 187 | Library | Description | | 187 | Library | Description | |
| 188 |---|---| | 188 |---|---| |
| 189 | <a href="https://api.dartlang.org/dart_indexed_db.html" target="_blank">dart:i
ndexed_db</a> | Save data into an indexed database for persistence and offline c
apability | | 189 | <a href="https://api.dartlang.org/dart_indexed_db.html" target="_blank">dart:i
ndexed_db</a> | Save data into an indexed database for persistence and offline c
apability | |
| 190 | <a href="https://api.dartlang.org/dart_async.html" target="_blank">dart:async<
/a> | Perform tasks asynchronously | | 190 | <a href="https://api.dartlang.org/dart_async.html" target="_blank">dart:async<
/a> | Perform tasks asynchronously | |
| 191 | <a href="https://api.dartlang.org/dart_core.html" target="_blank">dart:core</a
> | Use DateTime and Duration to manage time-related tasks | | 191 | <a href="https://api.dartlang.org/dart_core.html" target="_blank">dart:core</a
> | Use DateTime and Duration to manage time-related tasks | |
| 192 | <a href="https://api.dartlang.org/polymer.html" target="_blank">Polymer</a> |
Create UIs with custom elements and data binding. | | 192 | <a href="https://api.dartlang.org/polymer.html" target="_blank">Polymer</a> |
Create UIs with custom elements and data binding. | |
| 193 {: .table } | 193 {: .table } |
| 194 | 194 |
| 195 This tutorial explains the Dart API for IndexedDB used by the count_down app. | 195 This tutorial explains the Dart API for IndexedDB used by the count_down app. |
| 196 In addition, this tutorial covers some interesting | |
| 197 API related to dates, times, and timers. | |
| 198 | 196 |
| 199 <aside class="alert" markdown="1"> | 197 <aside class="alert alert-info" markdown="1"> |
| 200 <strong>Note:</strong> | 198 <strong>Note:</strong> |
| 201 This tutorial does not cover Futures or Polymer. | 199 This tutorial does not cover Futures or Polymer. |
| 202 For information about Futures, | 200 For information about Futures, |
| 203 see | 201 see |
| 204 <a href="/articles/using-future-based-apis/">Using Future Based APIs</a> | 202 <a href="/articles/using-future-based-apis/">Using Future Based APIs</a> |
| 205 and | 203 and |
| 206 <a href="/articles/futures-and-error-handling/">Futures and Error Handling</a>. | 204 <a href="/articles/futures-and-error-handling/">Futures and Error Handling</a>. |
| 207 For information about Polymer, | 205 For information about Polymer, |
| 208 refer to <a href="/docs/tutorials/polymer-intro/">Define a Custom Element</a>. | 206 refer to <a href="/docs/tutorials/polymer-intro/">Define a Custom Element</a>. |
| 209 | 207 |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 The first two parameters indicate the name and version of the | 331 The first two parameters indicate the name and version of the |
| 334 database to open. | 332 database to open. |
| 335 The first time the count_down app runs from a particular origin, | 333 The first time the count_down app runs from a particular origin, |
| 336 `milestoneDB` version 1 gets created and opened. | 334 `milestoneDB` version 1 gets created and opened. |
| 337 The next time the app runs from that same origin, | 335 The next time the app runs from that same origin, |
| 338 the database is simply opened. | 336 the database is simply opened. |
| 339 | 337 |
| 340 The third parameter, `onUpgradeNeeded`, | 338 The third parameter, `onUpgradeNeeded`, |
| 341 provides a callback function that gets called | 339 provides a callback function that gets called |
| 342 when an upgrade needed event is fired, | 340 when an upgrade needed event is fired, |
| 343 which happens when a new database | 341 which happens when a new database is created |
| 344 or the version of a database is updated. | 342 or the version of a database is updated. |
| 345 This gives your app an opportunity to create an object store. | 343 This gives your app an opportunity to create an object store. |
| 346 The only place you can create an object store | 344 The only place you can create an object store |
| 347 is within an upgrade needed event. | 345 is within an upgrade needed event. |
| 348 You _must_ have an object store to add records to the database. | 346 You _must_ have an object store to add records to the database. |
| 349 The next section covers how to create an object store. | 347 The next section covers how to create an object store. |
| 350 | 348 |
| 351 The following flow chart describes the logic of the | 349 The following flow chart describes the logic of the |
| 352 `window.indexedDB.open()` function. | 350 `window.indexedDB.open()` function. |
| 353 | 351 |
| 354  | 352  |
| 355 | 353 |
| 356 Because creating and opening a database can take time, | 354 Because creating and opening a database can take time, |
| 357 `window.indexedDB.open()` returns a Future object, | 355 `window.indexedDB.open()` returns a Future object, |
| 358 which runs asynchronously and returns a value sometime in the future. | 356 which runs asynchronously and returns a value, the database object, |
| 359 The value is returned to a callback function | 357 sometime in the future. |
| 358 The database object is returned to a callback function |
| 360 registered with `then()`. | 359 registered with `then()`. |
| 361 In this example, | 360 In this example, |
| 362 the callback function is called `_loadFromDB()`. | 361 the callback function is called `_loadFromDB()`. |
| 363 Using cursors, | 362 Using cursors, |
| 364 `_loadFromDB()` reads all the milestones | 363 `_loadFromDB()` reads all the milestones |
| 365 from the database and populates the app. | 364 from the database and populates the app. |
| 366 The details are covered in | 365 The details are covered in |
| 367 [Using a cursor to get all the records](#getting-data). | 366 [Using a cursor to get all the records](#getting-data). |
| 368 | 367 |
| 369 ##Creating an object store {#creating-object-store} | 368 ##Creating an object store {#creating-object-store} |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 403 Use the Database object's `createObjectStore()` method | 402 Use the Database object's `createObjectStore()` method |
| 404 to create a new object store with the given name. | 403 to create a new object store with the given name. |
| 405 Each object store must have a unique name. | 404 Each object store must have a unique name. |
| 406 The count_down app uses one object store called `milestoneStore`. | 405 The count_down app uses one object store called `milestoneStore`. |
| 407 All the countdown milestones are stored and retrieved | 406 All the countdown milestones are stored and retrieved |
| 408 in this object store. | 407 in this object store. |
| 409 | 408 |
| 410 The code sets `autoIncrement` on the object store to true. | 409 The code sets `autoIncrement` on the object store to true. |
| 411 When autoIncrement is true, | 410 When autoIncrement is true, |
| 412 the database generates unique, primary keys for you, | 411 the database generates unique, primary keys for you, |
| 413 which saves you the trouble of doing so. | 412 which saves you the trouble of ensuring unique keys. |
| 414 | 413 |
| 415 Finally, `_initializeDatabase` creates an index. | 414 Finally, `_initializeDatabase` creates a name index. |
| 416 | 415 |
| 417 ##Using a name index | 416 ##Using a name index |
| 418 | 417 |
| 419 An index provides a lookup table. | 418 An index provides a lookup table. |
| 420 You can associate a primary key with a field in the stored objects. | 419 You can associate a primary key with a field in the stored objects. |
| 421 In the example, | 420 In the example, |
| 422 the index associates a primary key with the milestoneName field. | 421 the index associates a primary key with the milestoneName field. |
| 423 | 422 |
| 424  | 423  |
| 425 | 424 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 449 In the count_down app, | 448 In the count_down app, |
| 450 if you try to add a milestone with the same name as another, | 449 if you try to add a milestone with the same name as another, |
| 451 it is this index that causes the add() to fail. | 450 it is this index that causes the add() to fail. |
| 452 | 451 |
| 453 ##Using transactions {#using-transactions} | 452 ##Using transactions {#using-transactions} |
| 454 | 453 |
| 455 All database operations must be performed | 454 All database operations must be performed |
| 456 within a | 455 within a |
| 457 <a href="https://api.dartlang.org/dart_indexedDb/Transaction.html" target="_blan
k">Transaction</a>. | 456 <a href="https://api.dartlang.org/dart_indexedDb/Transaction.html" target="_blan
k">Transaction</a>. |
| 458 | 457 |
| 459 <aside class="alert" markdown="1"> | 458 <aside class="alert alert-info" markdown="1"> |
| 460 <strong>Important: About the life-cycle of a transaction</strong> | 459 <strong>Important: About the life-cycle of a transaction</strong> |
| 461 | 460 |
| 462 The life-cycle of a transaction is as follows: | 461 The life-cycle of a transaction is as follows: |
| 463 | 462 |
| 464 * Open a transaction. | 463 * Open a transaction. |
| 465 * Place requests on the transaction and register callbacks. | 464 * Place requests on the transaction and register callbacks. |
| 466 * When there are no more requests | 465 * When there are no more requests |
| 467 and the last callback finishes, the transaction completes. | 466 and the last callback finishes, the transaction completes. |
| 468 | 467 |
| 469 So, a transaction remains alive until all requests are complete and | 468 So, a transaction remains alive until all requests are complete and |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 703 <a href="/articles/futures-and-error-handling/">Futures and Error Handling</a>
. | 702 <a href="/articles/futures-and-error-handling/">Futures and Error Handling</a>
. |
| 704 </li> | 703 </li> |
| 705 <li> | 704 <li> |
| 706 For information about Polymer, | 705 For information about Polymer, |
| 707 read <a href="/docs/tutorials/polymer-intro">Define a Custom Element</a>. | 706 read <a href="/docs/tutorials/polymer-intro">Define a Custom Element</a>. |
| 708 </li> | 707 </li> |
| 709 </ul> | 708 </ul> |
| 710 | 709 |
| 711 ###What next? | 710 ###What next? |
| 712 | 711 |
| 713 Check out our | 712 You've completed the tutorials! |
| 714 <a href="/codelabs/web-ui-writer/index.html" target="_blank"><i class="icon-beak
er"> </i>Codelab</a>; | 713 Check out the Dart |
| 715 it uses LocalStorage instead of IndexedDB to store data in the client. | 714 [code samples](/samples/) and [articles](/articles/). |
| 716 Try converting it to use IndexedDB. | |
| 717 | 715 |
| 718 {% endcapture %} | 716 {% endcapture %} |
| 719 | 717 |
| 720 {% include tutorial.html %} | 718 {% include tutorial.html %} |
| OLD | NEW |