Jake Drew
Jake Drew

Reputation: 2330

Why do I see "Type Error: cursor is undefined" when using indexedDB?

I am trying to use an index.openCursor(keyRange.only or keyRange.bound Provided here) to access one or more records using an index on a table created with autoIncrement: true. I have tried multiple variations with no success. Can someone show me a working example using the following code as a template:

window.indexedDB = window.indexedDB || window.webkitIndexedDB 
                || window.mozIndexedDB || window.msIndexedDB;
var ixDb; 

var ixDbIndexTest = function () {
  //Open or create the requested IndexedDB Database
  var ixDbRequest = window.indexedDB.open("testDBindexes", 2);

  ixDbRequest.onupgradeneeded = function (e) {
    ixDb = ixDbRequest.result || e.currentTarget.result;

    objectStore = 
      ixDb.createObjectStore("demoOS", 
                             { keyPath: "id", autoIncrement: true });
    objectStore.createIndex("ixdemo", "Field1",
                             { unique: false, multiEntry: false });

    //define new dummy record  
    var newRecord = {};
    newRecord.Field1 = "222";
    newRecord.Field2 = "333";
    newRecord.Field3 = "444";

    var request = objectStore.add(newRecord);

    request.onsuccess = function (e) {
      var index = objectStore.index('ixdemo');
      var range = IDBKeyRange.only("222");
      var cursorRequest = index.openCursor(range);

      cursorRequest.onsuccess = function(e) {    
        var cursor = cursorRequest.result || e.result; 
        alert(cursor.value);
        cursor.continue();
      }
    }
  };
};

window.onload = ixDbIndexTest;

Update: I modified the demo script to work in both Firefox and older Chrome versions that still use setVersion. However, you would need to add additional version checking logic for Chrome since the current logic runs setVersion every time the script runs.

window.indexedDB = window.indexedDB || window.webkitIndexedDB 
                || window.mozIndexedDB || window.msIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction 
                    || window.mozIDBTransaction || window.msIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || 
                     window.mozIDBKeyRange || window.msIDBKeyRange;

var ixDb;     
var ixDbIndexTest = function () {
  //Open or create the requested IndexedDB Database
  var ixDbRequest = window.indexedDB.open("testDBindexes", 1);

  ixDbRequest.onsuccess = function(e) {
    ixDb = ixDbRequest.result || e.currentTarget.result;

    if (typeof ixDb.setVersion === "function") {
      ixDbVersionRequest = ixDb.setVersion(1);

      ixDbVersionRequest.onsuccess = function (e) {
        indexTest();
      };
     }
     else {
       ixDbRequest.onupgradeneeded = function (e) {
       indexTest(); 
       };
     }
   }
 };

window.onload = ixDbIndexTest;

function indexTest() {
  var objectStore = ixDb.createObjectStore("demoOS", 
                           { keyPath: "id", autoIncrement: true });
  objectStore.createIndex("ixdemo", "Field1", 
                           { unique: false, multiEntry: false });

  //define new record with users input 
  var newRecord = {};
  newRecord.Field1 = "222";
  newRecord.Field2 = "333";
  newRecord.Field3 = "444";

  var request = objectStore.add(newRecord);

  request.onsuccess = function (e) {
    var index = objectStore.index('ixdemo');
    var range = IDBKeyRange.only("222");
    var cursorRequest = index.openCursor();

    cursorRequest.onsuccess = function(e) {    
      var cursor = cursorRequest.result || e.result; 
      if(cursor) {
        alert(JSON.stringify(cursor.value));
        cursor.continue();
      }
    }
  }
}

Upvotes: 1

Views: 3974

Answers (2)

dumbmatter
dumbmatter

Reputation: 9673

The error message Type Error: cursor is undefined happens because you are using the cursor without checking to see if it's defined. So when cursor.continue() tells IndexedDB to go get the next object in the database, the cursor will be undefined after it exhausts the only object that actually exists.

So you should do something like this. In your code, it would look like:

      cursorRequest.onsuccess = function(e) {    
        var cursor = cursorRequest.result || e.result;
        if (cursor) {
          alert(cursor.value);
          cursor.continue();
        }
      }

Also, if you know you are only looking for one object (like when you use IDBKeyRange.only), you can just omit the cursor.continue() part:

      cursorRequest.onsuccess = function(e) {    
        var cursor = cursorRequest.result || e.result;
        alert(cursor.value);
      }

As for your problem With Chrome, I can't help you there as I've only focused on Firefox so far. I would recommend you try the latest development version of Chrome, which actually does support onupgradeneeded along with various other updates, but in my testing so far it's still pretty buggy and code that works in Firefox can fail in Chrome. You might be better off just waiting some time for Chrome to stabilize, if this isn't an urgent project.

Upvotes: 4

Kyaw Tun
Kyaw Tun

Reputation: 13131

You cannot add records while in onupgardeneeded event.

after versing change, you must reopen the database to get new objectStore schema. so there will be two open

current chrome is, i think still old standard, setVersion, onupgardeneeded is never call.

newRecord must have keyPath 'id' or you should not specified keyPath in creating object store.

Upvotes: 0

Related Questions