ondrej
ondrej

Reputation: 997

How to handle async code that calls another async code [AngularJs]

I have factory that's using indexedDB and method getRecipe that needs this indexed db to receive data.

Problem is that indexedDB returns it's instance in asynchronous call and getRecipe is another method that returns it's value in asynchronous call.

I try to solve it via promises, but I failed.

app.factory('RecipesStorage', ['$q', function($q) { 
var getDb = function () {
   var deferred = $q.defer();

   var db;
   var request = indexedDB.open('recipes', 1);

   request.onupgradeneeded = function (e) {
       console.log('Upgrading indexedDb');
       var thisDb = e.target.result;

       if (!thisDb.objectStoreNames.contains('recipe')) {
           thisDb.createObjectStore('recipe');
       }
   }

   request.onsuccess = function (e) {
       db = e.target.result;
       window.db = db;
       deferred.resolve(db);
   }

   request.onerror = function (e) {
       console.error('Error when opening indexedDB');
   }

   return deferred.promise;
};

var getRecipe = function (recipeId, callback) {
        getDb().then(function(db) {
            var transaction = db.transaction(['recipe'], 'readonly');
            var objectStore = transaction.objectStore('recipe');

            var data = objectStore.get(recipeId);

            data.onsuccess = function (e) {
                var result = e.target.result;
                console.log('GetRecipe:', result);
                callback(result);
            }

            data.onerror = function (e) {
                console.error('Error retrieving data from indexedDB', e);
            }
        });
};

return {getRecipe:getRecipe};
}]);

But this doesent work. In getRecipe the function in then isn't invoked. I don't know where is problem.

Upvotes: 2

Views: 1546

Answers (3)

Maxim Shoustin
Maxim Shoustin

Reputation: 77930

We can use promise chain to make it work.

(I don't have database so i simulated async response and wrapped data with $q)

Demo Fiddle

fessmodule.controller('fessCntrl', function ($scope, RecipesStorage) {

    $scope.alertSwap = function () {
       RecipesStorage.getDb()
                        .then(function (result) {
                           $scope.data = result;                           
                        }, function (result) {
                            alert("Error: No data returned");
                        });
    }

});

fessmodule.$inject = ['$scope', 'RecipesStorage'];

fessmodule.factory('RecipesStorage', ['$q', function ($q) {

    var getDb = function () {        
        var data = [{
            "PreAlertInventory": "5.000000",
            "SharesInInventory": "3.000000"
        } ];   
        var deferred = $q.defer();
        deferred.resolve(data);
        return getRecipe(data);        
    };

    var getRecipe = function(db){    
        var data = [{        
            "TotalSharesBought": "0.000000",
            "TotalShareCost": "0.000000",
            "EstimatedLosses": "0.000000"
        }]; 
        db.push(data[0]);
        var deferred = $q.defer();
        deferred.resolve(db);
        return deferred.promise;
    }

    var factory = {
        getDb: getDb
    };

    return factory;
}]);

Reference

enter image description here

  • You can chain promises to create code flows
  • Error propagates, so you can catch it on the end of the chain

enter image description here

Upvotes: 3

ondrej
ondrej

Reputation: 997

The real problem was that in my version I've used angular in version 1.0.8, but when I switched it to version 1.2.0 it starts working as expected. Thanks :)

Upvotes: 0

lex82
lex82

Reputation: 11317

I can't see a problem in your code. Maybe this plunker helps you to figure out where the problem is. I created it based on your code and it apparently works.

Upvotes: 0

Related Questions