[Go] using the HTML5 IndexedDB API

Source: Internet
Author: User
Tags createindex

Local data persistence improves WEB application accessibility and mobile application responsiveness

The index Database (IndexedDB) API (as part of HTML5) is useful for creating data-intensive offline HTML5 WEB applications that have rich, locally stored data. It also helps to cache data locally, enabling traditional online Web applications, such as mobile Web applications, to run and respond faster. This article describes how to manage the IndexedDB database.

An important feature of HTML5 is the persistence of local data, which enables users to access WEB applications online and offline. In addition, local data persistence makes mobile applications more responsive, uses less bandwidth, and works more efficiently in low-bandwidth scenarios. HTML5 provides some local data persistence options. The first option is localstorage that it allows you to store data using a simple key-value pair. IndexedDB (a more powerful option) allows you to store a large number of objects locally and retrieve data using robust data access mechanisms.

The IndexedDB API replaces the WEB Storage API, which is deprecated in the HTML5 specification. (but some leading browsers still support Web Storage, including Apple's Safari and Opera Web browsers), and the IndexedDB has several advantages over web Storage, including indexing, transactional processing, and robust query functionality. This article will demonstrate how to manage the IndexedDB database through a series of examples. (See the download section for the full source code for the sample.) )

Important Concepts

A Web site may have one or more IndexedDB databases, and each database must have a unique name.

A database can contain one or more object stores . An object store (uniquely identified by a name) is a collection of records. Each record has a key and a value . The value is an object that can have one or more properties. The key may be based on a key generator, derived from a key path, or explicitly set. A key generator automatically generates a unique continuous positive integer. The key path defines the path to the key value. It can be a single JavaScript identifier or multiple identifiers separated by periods.

The specification contains an asynchronous API and a synchronization API. The synchronization API is used in a Web browser. Asynchronous APIs use requests and callbacks.

In the following example, the output is appended to a tag with an ID result div . To update result elements, you can clear and set properties during each data operation innerHTML . Each example JavaScript function is called by an event of an HTML button onclick .

Handling errors or exceptions and debugging

All asynchronous requests have a onsuccess callback and a callback, which is called when the onerror database operation succeeds, and is called when an operation is unsuccessful. Listing 1 is an onerror example of a callback.

Listing 1. Asynchronous error-handling functions
Request.onerror = function (e) {   //Handle error ...   Console.log ("Database error:" + E.target.errorcode);};

Using JavaScript try/catch blocks is a good idea when using the IndexedDB API. This feature is useful for handling errors and exceptions that can occur before a database operation, such as attempting to read or manipulate data when the database is not open, or attempting to write data when another read/write transaction is open.

IndexedDB is difficult to debug and troubleshoot, because in many cases the error message is generic and lacks information value. When developing an application, you can use console.log and JavaScript debugging tools, such as Firebug for Mozilla Firefox, or Chrome's built-in Developer tools. The value of these tools is invaluable for any JavaScript-intensive application, especially for HTML5 applications that use the IndexedDB API.

Back to top of page

Working with databases

A database can have only one version at a time. When the database is first created, its initial version number is 0. After a database is created, the database (and its object storage) can only be changed by a transaction of a versionchange particular type called. To change a database after it is created, you must open a database that has a higher version. This action triggers the upgradeneeded event. The code that modifies the database or object store must be upgradeneeded in the event handler.

The code snippet in Listing 2 shows how to create a database: Call the open method and pass the database name. If a database with the specified name does not exist, the database is created.

Listing 2. To create a new database
function CreateDatabase () {   var openrequest = LocalDatabase.indexedDB.open (dbName);   Openrequest.onerror = function (e) {      console.log ("Database error:" + E.target.errorcode);   };   openrequest.onsuccess = function (event) {      Console.log ("Database created");      localdatabase.db = Openrequest.result;   };   openrequest.onupgradeneeded = function (evt) {         ...   };}

To delete an existing database, you can call the deleteDatabase method and pass the name of the database you want to delete, as shown in Listing 3.

Listing 3. Delete an existing database
function DeleteDatabase () {   var deletedbrequest = localDatabase.indexedDB.deleteDatabase (dbName);   deletedbrequest.onsuccess = function (event) {      //database deleted successfully   };   Deletedbrequest.onerror = function (e) {      console.log ("Database error:" + E.target.errorcode);}   ;}

The code snippet in Listing 4 shows how to open a connection to an existing database.

Listing 4. Open the latest version of the database
function OpenDatabase () {   var openrequest = LocalDatabase.indexedDB.open ("dbName");   Openrequest.onerror = function (e) {      console.log ("Database error:" + E.target.errorcode);   };   openrequest.onsuccess = function (event) {      localdatabase.db = Openrequest.result;   };}

creating, deleting, and opening a database is as simple as that. Now is the time to use object storage.

Back to top of page

Using Object storage

An object store is a collection of data records. To create a new object store in an existing database, you need to version control the existing database. To do this, open the database for which you want to version control. In addition to the database name, the open method accepts a version number as the second parameter. If you want to create a new version of the database (that is, to create or modify an object store), simply open a database with a higher version of the existing database. This invokes the onupgradeneeded event handler function.

To create an object store, you can invoke the method on the database object createObjectStore , as shown in Listing 5.

Listing 5. Creating an Object Store
function Createobjectstore () {   var openrequest = LocalDatabase.indexedDB.open (dbName, 2);   Openrequest.onerror = function (e) {      console.log ("Database error:" + E.target.errorcode);   };   openrequest.onsuccess = function (event) {      localdatabase.db = Openrequest.result;   };   openrequest.onupgradeneeded = function (evt) {      var employeestore = Evt.currentTarget.result.createObjectStore         ("Employees", {keypath: "id"});}   ;}

We've learned how object storage works. Next, let's look at how the index references the object store that contains the data.

Back to top of page

Working with Indexes

In addition to using keys to retrieve records from an object store, you can also use a field that is indexed to retrieve records. An object store can have one or more indexes. An index is a special object store that references an object store that contains data that is automatically updated when changes are made to the referenced object store (that is, when records are added, modified, or deleted).

To create an index, you must use the method shown in Listing 5 to make the database version-controlled. The index can be unique, or it can be inflexible. A unique index requires that all values in the index are unique, such as using an e-mail address field. When a value can recur, you need to use a non-unique index, such as city, state, or country. The code snippet in Listing 6 shows how to create a non-unique index on the state field of the Employee object, create a non-unique index on the ZIP Code field, and create a unique index on the email address field:

Listing 6. Create an index
function CreateIndex () {   var openrequest = LocalDatabase.indexedDB.open (dbName, 2);   Openrequest.onerror = function (e) {      console.log ("Database error:" + E.target.errorcode);   };   openrequest.onsuccess = function (event) {      db = Openrequest.result;   };   openrequest.onupgradeneeded = function (evt) {     var employeestore = Evt.currentTarget.result.objectStore (" Employees ");     Employeestore.createindex ("Stateindex", "state", {unique:false});     Employeestore.createindex ("Emailindex", "email", {unique:true});     Employeestore.createindex ("Zipcodeindex", "Zip_Code", {unique:false})   };

Next, you will use transactions to perform some operations on the object store.

Back to top of page

Using transactions

You need to use transactions to perform all read and write operations on the object store. Similar to how transactions in a relational database work, the IndexedDB transaction provides an atomic collection of database writes that are either fully committed or not committed at all. IndexedDB transactions also have a abort and commit tool for database operations.

Table 1 lists and describes the transaction modes provided by the IndexedDB.

Table 1. IndexedDB Transaction Mode
Mode Description
readonly Provides read-only access to an object store and is used when querying object storage.
readwrite Provides read and write access to an object store.
versionchange Provides read and write access to modify the object storage definition, or create a new object store.

The default transaction mode is readonly . You can open multiple concurrent transactions at any given time readonly , but only one transaction can be opened readwrite . For this reason, the use of transactions is only considered when data is updated readwrite . versionchangea single database or object store that represents a transaction operation that cannot open any other concurrent transaction. You can onupgradeneeded use transactions in an event handler to versionchange Create, modify, or delete an object store, or to add an index to an object store.

To readwrite create a transaction in the schema for the employees object store, you can use the statement: var transaction = db.transaction("employees", "readwrite"); .

The JavaScript function in Listing 7 shows how to use a transaction to retrieve employees a specific employee record in the object store using a key.

Listing 7. Use keys to get a specific record
function Fetchemployee () {try {   var result = document.getElementById ("result");   result.innerhtml = "";   if (localdatabase = null && localdatabase.db! = null) {     var store = localDatabase.db.transaction ("Employees" ). ObjectStore ("Employees");     Store.get ("E3"). onsuccess = function (event) {      var employee = Event.target.result;      if (employee = = null) {         Result.value = "Employee not found";      }      else {         var jsonstr = json.stringify (employee);         result.innerhtml = Jsonstr;}}     ;   } catch (e) {   console.log (e);}}

The JavaScript function in Listing 8 shows how to use a transaction to retrieve a emailIndex employees specific employee record in an object store using an index instead of an object store key.

Listing 8. Using indexes to get specific records
function Fetchemployeebyemail () {try {   var result = document.getElementById ("result");   result.innerhtml = "";   if (localdatabase! = NULL && localdatabase.db! = null) {      var range = idbkeyrange.only ("[email protected]"); 
   var store = localDatabase.db.transaction ("Employees"). ObjectStore ("Employees");      var index = store.index ("Emailindex");      Index.get (range). onsuccess = function (evt) {         var employee = Evt.target.result;         var jsonstr = json.stringify (employee);         result.innerhtml = jsonstr;}      ;}   } catch (e) {

Listing 9 is readwrite An example of using transactions to create a new employee record.

Listing 9. Create a new employee record
function AddEmployee () {try {var result = document.getElementById ("result");      result.innerhtml = "";      var transaction = localDatabase.db.transaction ("Employees", "ReadWrite");      var store = Transaction.objectstore ("Employees");            if (localdatabase! = NULL && localdatabase.db! = null) {var request = Store.add ({"id": "E5",            "First_Name": "Jane", "last_name": "Doh", "email": "[email protected]", "Street": "123 Pennsylvania Avenue", "City": "Washington D.C.", "state": "DC", "Zip_         Code ":" 20500 ",});         request.onsuccess = function (e) {result.innerhtml = "Employee record was added successfully.";         };            Request.onerror = function (e) {console.log (e.value);         result.innerhtml = "Employee record is not added.";      };   }} catch (e) {console.log (e); }}

Listing 10 is readwrite An example of updating an existing employee record with a transaction. This example changes the E3 e-mail address of the employee who has the record ID.

Listing 10. Update an existing employee record
function UpdateEmployee () {try {var result = document.getElementById ("result");   result.innerhtml = "";   var transaction = localDatabase.db.transaction ("Employees", "ReadWrite");   var store = Transaction.objectstore ("Employees");   var jsonstr;   var employee;         if (localdatabase = null && localdatabase.db! = null) {Store.get ("E3"). onsuccess = function (event) {         Employee = Event.target.result;         Save old value Jsonstr = ' old: ' + json.stringify (employee);         result.innerhtml = Jsonstr;         Update record employee.email = "[email protected]";         var request = Store.put (employee);         request.onsuccess = function (e) {console.log ("Added Employee");         };         Request.onerror = function (e) {console.log (e.value);         };            Fetch record again Store.get ("E3"). onsuccess = function (event) {employee = Event.target.result; Jsonstr = "
NEW: "+ json.stringify (employee); result.innerhtml = result.innerhtml + jsonstr; }; Fetch employee AGAIN}; Fetch Employee first time}}catch (e) {console.log (e);}}

Listing 11 is an example of a transaction that creates or deletes all records in an object store readwrite . Like other asynchronous transactions, a clear transaction invokes or callbacks based on whether the object store has been purged onsuccess onerror .

Listing 11. Clear Object Store Transactions
function clearallemployees () {try {   var result = document.getElementById ("result");   result.innerhtml = "";   if (localdatabase = null && localdatabase.db! = null) {     var store = localDatabase.db.transaction ("Employees" , "ReadWrite"). ObjectStore ("Employees");     Store.clear (). onsuccess = function (event) {      result.innerhtml = "' Employees ' object store cleared";     };   } catch (e) {   console.log (e);}}

These examples illustrate some of the common uses of transactions. Next you'll see how the IndexedDB midstream works.

Back to top of page

Using cursors

Similar to how a relational database works, cursors in IndexedDB enable you to iterate over a record in an object store. You can also use an index of object storage to iterate over records. Cursors in IndexedDB are bidirectional, so you can iterate through records forward and backward, and you can skip duplicate records in non-unique indexes. openCursormethod to open a cursor. It accepts two optional parameters, including the range and direction.

Listing 12 employees opens a cursor for the object store and iterates through all employee records.

Listing 12. Iterate all Employee records
function fetchallemployees () {try {   var result = document.getElementById ("result");   result.innerhtml = "";   if (localdatabase = null && localdatabase.db! = null) {      var store = localDatabase.db.transaction ("Employees" ). ObjectStore ("Employees");      var request = Store.opencursor ();      request.onsuccess = function (evt) {         var cursor = Evt.target.result;         if (cursor) {            var employee = Cursor.value;            var jsonstr = json.stringify (employee);            result.innerhtml = result.innerhtml + "
"+ jsonstr; Cursor.continue ();}} ;} } catch (e) { console.log (e);}}

The following examples use cursors for indexing. Table 2 lists and describes the scope types or filters that the IndexedDB API provides when you open a cursor for an index.

Table 2. The scope type or filter provided by the IndexedDB API when the cursor is opened for the index
idbkeyrange.bound returns all records in the specified range. This range has a lower and upper boundary. It also has two optional parameters: loweropen   and Upperopen , which indicate whether records on the lower or upper bounds should be included in the range.
idbkeyrange.lowerbound All records that exceed the specified boundary value range. This range has an optional parameter   loweropen , which indicates whether the records on the lower boundary should be included in the scope.
idbkeyrange.upperbound returns all records before the specified boundary value. It also has an optional   upperopen   parameters.
idbkeyrange.only returns only records that match the specified value.

Listing 13 is a basic example of all employee records for an iteration of a specific country. This query is most common. It enables you to retrieve all records that match a specific condition. This example uses stateIndex and IDBKeyRange.only ranges to return all records that match the specified value (in this case "New York" ).

Listing 13. Iterate all employee records in New York City.
function fetchnewyorkemployees () {try {   var result = document.getElementById ("result");   result.innerhtml = "";   if (localdatabase! = NULL && localdatabase.db! = null) {      var range = idbkeyrange.only ("New York");      var store = localDatabase.db.transaction ("Employees"). ObjectStore ("Employees");      var index = store.index ("Stateindex");      Index.opencursor (range). onsuccess = function (evt) {         var cursor = Evt.target.result;         if (cursor) {            var employee = Cursor.value;            var jsonstr = json.stringify (employee);            result.innerhtml = result.innerhtml + "
"+ jsonstr; Cursor.continue ();}} ;} } catch (e) { console.log (e);}}

Listing 14 is an IDBKeyRange.lowerBound example of using scopes. It iterates all employees with a zip code above 92000.

Listing 14. Use IDBKeyRange.lowerBound
function FetchEmployeeByZipCode1 () {try {   var result = document.getElementById ("result");   result.innerhtml = "";   if (localdatabase = null && localdatabase.db! = null) {     var store = localDatabase.db.transaction ("Employees" ). ObjectStore ("Employees");     var index = store.index ("Zipindex");     var range = Idbkeyrange.lowerbound ("92000");     Index.opencursor (range). onsuccess = function (evt) {      var cursor = Evt.target.result;      if (cursor) {         var employee = Cursor.value;         var jsonstr = json.stringify (employee);         result.innerhtml = result.innerhtml + "
"+ jsonstr; Cursor.continue ();}} ;} } catch (e) { console.log (e);}}

Listing 15 is an IDBKeyRange.upperBound example of using scopes. It iterates over all employees whose ZIP code is based on 93000.

Listing 15. Use IDBKeyRange.upperBound
function FetchEmployeeByZipCode2 () {try {   var result = document.getElementById ("result");   result.innerhtml = "";   if (localdatabase = null && localdatabase.db! = null) {     var store = localDatabase.db.transaction ("Employees" ). ObjectStore ("Employees");     var index = store.index ("Zipindex");     var range = Idbkeyrange.upperbound ("93000");     Index.opencursor (range). onsuccess = function (evt) {      var cursor = Evt.target.result;      if (cursor) {         var employee = Cursor.value;         var jsonstr = json.stringify (employee);         result.innerhtml = result.innerhtml + "
"+ jsonstr; Cursor.continue ();}} ;} } catch (e) { console.log (e);}}

Listing 16 is an IDBKeyRange.bound example of using scopes. It retrieves all employees whose postal code values are between 92000 and 92999 (inclusive).

Listing 16. Use IDBKeyRange.bound
function fetchEmployeeByZipCode3 () {try {   var result = document.getElementById ("result");   result.innerhtml = "";   if (localdatabase = null && localdatabase.db! = null) {     var store = localDatabase.db.transaction ("Employees" ). ObjectStore ("Employees");     var index = store.index ("Zipindex");     var range = Idbkeyrange.bound ("92000", "92999", true, true);     Index.opencursor (range). onsuccess = function (evt) {      var cursor = Evt.target.result;      if (cursor) {         var employee = Cursor.value;         var jsonstr = json.stringify (employee);         result.innerhtml = result.innerhtml + "
"+ jsonstr; Cursor.continue ();}} ;} } catch (e) { console.log (e);}}

These examples show that the cursor functionality in IndexedDB is similar to the cursor functionality in a relational database. Using the IndexedDB cursor, you can iterate over the records in an object store and the records of an index stored by an object. Cursors in the IndexedDB are bidirectional, providing additional flexibility.

Back to top of page

Conclusion

The IndexedDB API is so powerful that you can use it to create data-intensive applications with rich local storage data (especially offline HTML5 WEB applications). You can also use the IndexedDB API to cache data locally so that traditional online Web applications, especially mobile Web applications, can run and respond faster, eliminating the need to retrieve data from the WEB server every time. For example, you can cache data from a picklist in a IndexedDB database.

This article shows how to manage a IndexedDB database, including creating a database, deleting a database, and establishing a connection to a database. This article also shows many of the more advanced features of the IndexedDB API, including transactional processing, indexing, and cursors. You can use these presentation concepts to build offline apps or mobile WEB applications that take advantage of the IndexedDB API.

[Go] using the HTML5 IndexedDB API

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.