Search code examples
javascriptjqueryindexeddbjquery-deferredcanjs

Deferred then of then is undefined for IndexedDb


I'm using CanJs and I'm learning jquery deferred but I have a problem. I created a controller as sort of Singleton to manage data in IndexedDb.

First of all, I created an openDb function like this:

openDbDeferred: null,

    openDb: function (dbName, dbVersion) {
        console.log('Open DB...');

        var openDbDeferred = this.openDbDeferred;

        if (!openDbDeferred || openDbDeferred.isRejected()) {
            openDbDeferred = $.Deferred();

            var db;
            var req = indexedDB.open(dbName, dbVersion);

            req.onsuccess = function (evt) {
                db = this.result;
                console.log('openDB SUCCESS');
                openDbDeferred.resolve(db);
            };

            req.onerror = function (evt) {
                console.error("[ERROR] openDb: " + evt);
                openDbDeferred.reject();
            };

            req.onupgradeneeded = function (evt) {
                console.log('openDb.onupgradeneeded');
                var db = evt.target.result;
                var store = db.createObjectStore('sessioni', {keyPath: 'idSession'});

                store.createIndex('by_url', 'url', {unique: false});
                store.createIndex('by_startDate', 'startDate', {unique: false});
                store.createIndex('by_endDate', 'endDate', {unique: false});
            };

        }
        return openDbDeferred.promise();
    }

Then I created a function to retrieve all data in DB:

getFilesList: function () {
        var getDataDeferred;
        return this.openDb('session-db', 1).then(function (db) {
            console.log('Find all records...');

            getDataDeferred = $.Deferred();
            var tx = db.transaction("sessioni", "readwrite");
            var store = tx.objectStore("sessioni");
            var items = [];

            tx.oncomplete = function() {
                //console.log(items);
                getDataDeferred.resolve(items);
                console.log('Transazione getFilesList completata');
            };

            tx.onfailure = function(evt) {
                getDataDeferred.reject();
                console.error('[ERROR] Transazione getFilesList fallita: ' + evt);
            };

            var cursorRequest = store.openCursor();

            cursorRequest.onsuccess = function (evt) {
                var cursor = evt.target.result;
                if (cursor) {
                    items.push(cursor.value);
                    cursor.continue();
                }
            };
            cursorRequest.onerror = function (error) {
                console.error('findAll [ERROR]: ' + error);
            };
        });

        return getDataDeferred.promise();
    }

I declared this controller in another controller to call getFilesList function:

retreiveAllData: function() {
        return this.sessionManageModel.getFilesList().than(function(items) {
            console.log(items)
            return items;
        });
    }

When the retreiveAllData function is called, it returns 'undefined' because items is 'undefined'.

How can I obtain items in retreiveAllData function?


Solution

  • You've got two return statements in your getFilesList function. The second one should actually be inside the then callback - which currently returns undefined as you observe.

    getFilesList: function () {
        // no need to declare deferred variable outside of the callback
        return this.openDb('session-db', 1).then(function (db) {
            var getDataDeferred = $.Deferred();
            … // do all the stuff
            return getDataDeferred; // place the `return` here
        }); 
        // not here!
    }