William Thomas
William Thomas

Reputation: 2126

Object has no method "open" error when using indexedDB

I'm trying to build a small class-like container that will make it a little cleaner to load and store data from the HTML5 IndexedDB. To be honest this is the first time I've ever played with this feature, so my issue could be trivial.

I'm basing my code off of this tutorial: http://www.html5rocks.com/en/tutorials/indexeddb/todo/

function DBDictionary()
{
    this.Holder = {};
    this.Entries = new Array();
    this.Opened = false;
    this.v = "1.0";
    this.Holder.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB;

    if ('webkitIndexedDB' in window)
    {
        window.IDBTransaction = window.webkitIDBTransaction;
        window.IDBKeyRange = window.webkitIDBKeyRange;
    }

    this.Holder.indexedDB = {};
    this.Holder.indexedDB.db = null;

    this.Holder.indexedDB.onerror = function(e) 
    {
        console.log(e);
    };

    this.DownloadDB = function()
    {
        if(this.Opened) return;
        var request = this.Holder.indexedDB.open("Storage");
        request.onsuccess = function(e)
        {
            this.Holder.indexedDB.db = e.target.result;
            var db = this.Holder.indexedDB.db;
            // We can only create Object stores in a setVersion transaction;
            if (v!= db.version)
            {
                var setVrequest = db.setVersion(v);

                // onsuccess is the only place we can create Object Stores
                setVrequest.onerror = this.Holder.indexedDB.onerror;
                setVrequest.onsuccess = function(e)
                {
                    if(db.objectStoreNames.contains("Storage")) db.deleteObjectStore("Storage");
                    var store = db.createObjectStore("Storage", {keyPath: "Key"});
                    this.PopulateAll();
                };
            }
            else
            {
                this.PopulateAll();
            }
        };

        request.onerror = this.Holder.indexedDB.onerror;
    };

    this.UploadDB = function()
    {       
        this.DeleteAll();
        this.SaveAll();
    };

    this.DeleteAll = function()
    {
        var db = this.Holder.indexedDB.db;
        var trans = db.transaction(["Storage"], IDBTransaction.READ_WRITE);
        var store = trans.objectStore("Storage");

        Entries.forEach(function(element, index, array)
        {
            var request = store.delete(index);

            request.onerror = function(e)
            {
                console.log("Error Deleting: ", e);
            };
        });
    };

    this.PopulateAll = function()
    {
        var db = this.Holder.indexedDB.db;
        var trans = db.transaction(["Storage"], IDBTransaction.READ_WRITE);
        var store = trans.objectStore("Storage");

        // Get everything in the store;
        var keyRange = IDBKeyRange.lowerBound(0);
        var cursorRequest = store.openCursor(keyRange);

        cursorRequest.onsuccess = function(e)
        {
            var result = e.target.result;

            //No more results to load
            if(!!result == false)
            {
                if(!this.Opened) this.Opened = true;
                return;
            }

            this.Entries[result.Key] = result.Value;
            result.continue();
        };

        cursorRequest.onerror = this.Holder.indexedDB.onerror;
    };

    this.SaveAll = function()
    {
        var db = this.Holder.indexedDB.db;
        var trans = db.transaction(["Storage"], IDBTransaction.READ_WRITE);
        var store = trans.objectStore("Storage");

        Entries.forEach(function(element, index, array)
        {
            var data = {
                "Key": index,
                "Value": element,
                "timeStamp": new Date().getTime()
            };

            var request = store.put(data);

            request.onerror = function(e) {
                console.log("Error Adding: ", e);
            };
        });
    };
}

function main()
{
    var dictionary = new DBDictionary();
    dictionary.DownloadDB();

    dictionary.Entries["hello"] = "world";
    alert(dictionary.Entries["hello"]);
}

$(document).ready(main);

My desired implemented state should look something like this:

function main()
{
    var dictionary = new DBDictionary();
    dictionary.DownloadDB();

    dictionary.Entries["hello"] = "world";
    alert(dictionary.Entries["hello"]);
}

$(document).ready(main);

What this should do is download the data from the browser's IndexedDB object and store them into the object-housed array Entries. When I want to store the value of Entires back into the DB, I would call dictionary.UploadDB();

However, I'm getting the single javascript error: Uncaught TypeError: Object # has no method 'open'. I'm pretty much at a loss as to what I'm doing wrong. Can anyone offer me some tips?

Upvotes: 2

Views: 1689

Answers (1)

buley
buley

Reputation: 29308

Do a typeof check and console.log the this.Holder.indexedDB object to inspect the prototype. Does it inherit the IDBDatabase prototype? If it does, the open method would be available to you.

If your window.indexedDB did fire the on success callback, e.target.result would be the correct way to access the newly opened database via the event object. But the fact that you're not getting that far suggests that your this.Holder.indexedDB object is not actually an instance of an IDBDatabase.

EDIT: Yes, this is exactly your issue. If you console.log the this.holder.indexedDB object you get an object that looks like {"db":null}.

Swap this.Holder.indexedDB for window.webkitIndexedDB at your open invocation and you'll see that 'world' alert pops. JSFiddle here.

Upvotes: 2

Related Questions