Giter Club home page Giter Club logo

angular-indexeddb's Introduction

angular-indexed-db

build status

An AngularJS service provider to utilize indexedDB with angular

##Release Notes

1.1.1

Bugfix release. Addresses a problem with opening multiple stores and a problem with using this library in non-native indexedDB environments.

1.1.0

Lots of changes. The way of interacting with stores has changed so that you can operate more transaction-aware. Many things did not work in the prior version correctly. The service is now well tested and the base build is written in coffeescript.

Installation

For installation the use of Bower is recommended.

Bower

Call the following command on your command line:

bower install --save angular-indexed-db

And add the following line to your html file, for example index.html:

<script src="bower_components/angular-indexedDB/angular-indexed-db.js"></script>

Manual

  • Download file.
  • Add the following line to your html file:
<script src="angular-indexed-db.js"></script>

Usage

Normally, and as a recommendation, you have only one indexedDB per app. Thus in your app.js where you define your module, you do:

angular.module('myModuleName', ['indexedDB'])
  .config(function ($indexedDBProvider) {
    $indexedDBProvider
      .connection('myIndexedDB')
      .upgradeDatabase(1, function(event, db, tx){
        var objStore = db.createObjectStore('people', {keyPath: 'ssn'});
        objStore.createIndex('name_idx', 'name', {unique: false});
        objStore.createIndex('age_idx', 'age', {unique: false});
      });
  });

The connection method takes the databasename as parameter, the upgradeCallback has 3 parameters: function callback(event, database, transaction). AngularJS-indexedDB supports incremental upgrades. Simply define what to do for each version incrementally:

angular.module('myModuleName', ['indexedDB'])
  .config(function ($indexedDBProvider) {
    $indexedDBProvider
      .connection('myIndexedDB')
      .upgradeDatabase(1, function(event, db, tx){
        var objStore = db.createObjectStore('people', {keyPath: 'ssn'});
        objStore.createIndex('name_idx', 'name', {unique: false});
        objStore.createIndex('age_idx', 'age', {unique: false});
      });
      .upgradeDatabase(2, function(event, db, tx){
        db.createObjectStore('peoplePhones', {keyPath: 'person_ssn'});
      });
  });

When upgrade is required only the migrations which have not been run yet will be run. For upgrading your db structure, see https://developer.mozilla.org/en-US/docs/IndexedDB/Using_IndexedDB.

You can also define your own error handlers, overwriting the default ones, which log to console.

Inside your controller you use $indexedDB like this:

angular.module('myModuleName')
  .controller('myControllerName', function($scope, $indexedDB) {
    
    $scope.objects = [];
        
    $indexedDB.openStore('people', function(store){
    
      store.insert({"ssn": "444-444-222-111","name": "John Doe", "age": 57}).then(function(e){...});
    
      store.getAll().then(function(people) {  
        // Update scope
        $scope.objects = people;
      });
    });
  });

openStore

When you open a store a transaction is created for all of your actions against that store you receive a promise for each operation within your transaction and also for the transaction as a whole as the result of "openStore". The transaction resolves successfully after state has been fully persisted.

store operations

The following operations are allowed on a store..

  • getAllKeys - Returns all the primary keys on the store
    $indexedDB.openStore('people', function(store){
      store.getAllKeys().then(function(e){
        $scope.primaryKeys = e;
      });
    });
  • clear - Deletes all items from the store
    $indexedDB.openStore('people', function(store){
      store.clear().then(function(){
        // do something
      });
    });
  • delete - Deletes a single item from the store
    $indexedDB.openStore('people', function(store){
      store.delete($scope.personID).then(function(){
        // do something
      });
    });
  • upsert - Upserts an item or list of items in the store
    // build photo array to upsert
    var addToPhotos = [];
    for(var j=0; j < file.length; j++){
        var photo = {"topicID": $scope.topicID, "filetype": file[j].filetype, "content": file[j].base64}
        addToPhotos.push(photo);
    }
    
    $indexedDB.openStore('people', function(store){
      
      // multiple items
      store.upsert(addToPhotos).then(function(e){
        // do something
      });
      
      // single item
      store.upsert({"id": $scope.topicID, "name": $scope.topicName}).then(function (e) {
        // do something
      });
    });
  • insert - Inserts an item or list of items in the store
    // build photo array to upsert
    var addToPhotos = [];
    for(var j=0; j < file.length; j++){
        var photo = {"topicID": $scope.topicID, "filetype": file[j].filetype, "content": file[j].base64}
        addToPhotos.push(photo);
    }
    
    $indexedDB.openStore('people', function(store){
      
      // multiple items
      store.insert(addToPhotos).then(function(e){
        // do something
      });
      
      // single item
      store.insert({"id": $scope.topicID, "name": $scope.topicName}).then(function (e) {
        // do something
      });
    });
  • getAll - Returns all items in the store
    $indexedDB.openStore('people', function(store){
      store.getAll().then(function(topics) {  
        // Update scope
        $scope.topics = topics;
      });
    });
  • each - iterates over all items in the store
  • eachBy - iterates over all items in the store using a named index.
  • eachWhere - uses the query() to execute a find against the store
$indexedDB.openStore('photos', function(photos){
  // build query
  var find = photos.query();
  find = find.$eq($scope.topicID);
  find = find.$index("topicID_idx");
  
  // update scope
  photos.eachWhere(find).then(function(e){
      $scope.photos = e;
  });
});
  • findWhere - an alias for eachWhere
  • count - returns a count of all the items
    $indexedDB.openStore('people', function(store){
      store.count().then(function(e){
        $scope.count = e;
      });
    });
  • find - returns a single item from the store
$indexedDB.openStore('photos', function(photos){
  photos.find($scope.key).then(function(e){
      $scope.photo = e;
  });
});
  • findBy - searches a particular index for an item
$indexedDB.openStore('photos', function(photos){
  photos.findBy($scope.indexName, $scope.key).then(function(e){
      $scope.photo = e;
  });
});
  • query - builds a new query obect for use against eachWhere
var find = photos.query();
find = find.$eq($scope.topicID);
find = find.$index("topicID_idx");

// available query functions
  $lt(value) - less than
  $gt(value) - greater than
  $lte(value) - less than or equal
  $gte(value) - greater than or equal
  $eq(value) - equal
  $between(lower, upper, doNotIncludeLowerBound? true/false, doNotIncludeUpperBound true/false) - between two bounds
  $desc(unique) - descending order
  $asc(unique) - ascending order
  $index(value) - name of index

angular-indexeddb's People

Contributors

bramski avatar corwin-of-amber avatar crewjam avatar derekroth avatar devgru avatar hamstercat avatar jazo avatar joebordes avatar krymen avatar mmmichl avatar qiuzuhui avatar slebrequier avatar stephenradachy avatar thvd avatar tlvince avatar tomaszkrym avatar vitaliy-zinchenko avatar webcss avatar wibimaster avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

angular-indexeddb's Issues

Move all code inside the module definition

Currently, the following lines are outside of the angular.module definition, which means they run immediately when the file is loaded, rather than waiting for angular.bootstrap to occur.

var IDBKeyRange, indexedDB,
  __slice = [].slice;

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

IDBKeyRange = window.IDBKeyRange || window.mozIDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;

The problem is that if I'm running in a browser that doesn't natively support IndexedDB, and I'm loading a polyfill instead, then the above code will only work if the polyfill is loaded before the angular-indexed-db.js file. But if the polyfill is being loaded dynamically (say, as an Angular module, a Require.js module, a Browserify package, or a Cordova plugin), then the polyfill won't load in time, and Angular-IndexedDB won't work.

To fix this problem, the four lines of code shown above just need to be moved inside of the angular.module definition. That way, they won't run until all dynamically-loaded scripts are finished loading and angular.bootstrap is called.

How to page?

Hi bramski,
Thanks for your work. I'm new to angularjs and I'm trying to use this useful library in my project. My question is: I know indexeddb use cursor. Can I use it to implement a pagination function with angular-indexedDB library. I didn't found a function to access the cursor.

Best regards
Giuseppe

Failed to execute 'add' on 'IDBObjectStore': An object could not be cloned.

Hi bramski
I have a problem using angular-indexedDB module with Restangular.
Failed to execute 'add' on 'IDBObjectStore': An object could not be cloned.
I try to run:
Restangular.one(entityName, id).get().then(function(result) {
$indexedDB.openStore(entityName, function(table) {
table.insert(result, function(result) {
console.log('insert ok');
});
});
});

Is possible to use your module with Restangular or an openStore after a promise result?

Thanks for your help.

Gaspare

Could you please provide some usage examples ?

Usage examples are helpful for figure out how to use this library.

Especially, I like to know how to get the database object for binding onerror event for error handling globally like :

db.onerror = function(event) {
  // Generic error handler for all errors targeted at this database's
  // requests!
  alert("Database error: " + event.target.errorCode);
};

Thank you very much.

Feature: Safari 8 Support

Hello,

have you tested it on Safari?
I'm running an app successfully on Chrome and FF on Mac, but Safari is not ok, but not giving any error.

Thanks,
Mitch

Is the DbQ object really necessary? Why not just use $q

I found the deleteDatabase method wasn't deleting my database correctly; it was clearing the stores I had contained within it but not deleting the database itself. The approach used is a little puzzling - why does this service make use of a DbQ wrapper, and why this functionality is needed over the $q service that comes with angular? Maybe I'm missing something...

original (not working as expected)

deleteDatabase: function () {
    return closeDatabase().then(function () {
        var defer;
        defer = new DbQ();
        defer.resolveWith(indexedDB.deleteDatabase(dbName));
            return defer.promise;
        })["finally"](function () {
            return $log.log("$indexedDB: " + dbName + " database deleted.");
        });
    }

modified (working)

deleteDatabase: function () {
    return closeDatabase().then(function() {
        var deferred = $q.defer();

        indexedDB.deleteDatabase(dbName).then(function (result) {
            console.log("$indexedDB: " + dbName + " database deleted.")
            deferred.resolve(result);
        }).catch(function(error) {
            deferred.reject(error);
        });

        return defer.promise;
    });
}

Is it just outdated? I can submit a pull request if you'd like.

Please add support for retrieving keys

The current implementation only supports to retrieve values in getAll, each, etc. Please also add methods to retrieve the keys in combination with the values as the keys are necessary for example for deletion, e.g.:

ObjectStore.prototype.getAllKeyValues = function() {
   var defer;
   defer = this.defer();
    if (this.store.getAll) {
       defer.resolveWith(this.store.getAll());
    } else {
       this._mapCursor(defer, function(cursor) {
         return {key:cursor.key, value:cursor.value};
        });
    }
     return defer.promise;
};

Just provide a map with "key" and "value" attributes.

Mathias

Need help creating complex keys

I'm new to indexedDB and trying to create complex keys as the example below, but it is giving me error

var aStore = db.createObjectStore('aStore', {keyPath: ['a_id', 'b_code']});
a.createIndex('c_idx', {'c' : ['c.d', 'c.f']} , {unique: false});

ERROR
Uncaught SyntaxError: Failed to execute 'createIndex' on 'IDBObjectStore': The keyPath argument contains an invalid key path.(anonymous function) @ app.js:29applyNeededUpgrades @ angular-indexed-db.js:52dbReq.onupgradeneeded @ angular-indexed-db.js:131
angular.js:10627 $indexedDB: myIndexedDB database deleted.

Examples using angular-indexedDB to create/use complex keys are much appreciated

Thanks!

Is querying over multi entry indexes implemented?

I'm trying to query against an index that's multi entry (array of strings as key), and getting empty results.
Am I missing something or is it not implemented in the repository?

Here's the code I'm using:

$scope.searchStaff = function(staff){
  $indexedDB.openStore('records', function(store){
    $scope.lostone = staff.name;
    var find = store.query();
    find = find.$eq($scope.lostone);
    find = find.$index("pax_idx");
    store.eachWhere(find).then(function(e){
        $scope.foundstaff = e;
        console.log($scope.foundstaff);
    });
  });
};

Maybe it' s issue... :)

At first,

I want to thank you for great module! You saved my time & life. ;)

I found this little bug:

$indexedDB.openStore('articles', function (store) {
            var find = store.query();
            find = find.$eq($routeParams.id);
            find = find.$index("category_id_idx");
            store.eachWhere(find).then(function (e) {
                console.log('found', e);
                $scope.articles = e;
            }, function () {
                console.log('not found');
            });
        });

This doesn't work, you have to:

parseInt($routeParams.id) 

to make it work...
If you could place this in to manual.

Thanks!

Provide nice way to insert data during config

Unless I'm reading this wrong, I think to insert data during config/upgrade time you need to go through the native objects, transactions, etc. It would be nice to get the same interface that $indexedDB.openStore gives you.

How to filter against multiple indexes?

I'm trying to figure out how I can filter my data against multiple columns.

The schema for the object being stored in indexeddb is:

"Environment": { type: "string", editable: false, nullable: false },
"SequenceId": { type: "string", editable: false, nullable: false },
"LogLevel": { type: "string", editable: false, nullable: false },
"ServerTime": { type: "date", editable: false, nullable: false },
"Program": { type: "string", editable: false, nullable: false },
"Subject": { type: "string", editable: false, nullable: true },
"Message": { type: "string", editable: false, nullable: true },
"Exception": { type: "string", editable: false, nullable: true },
"User": { type: "string", editable: false, nullable: false },
"MachineName": { type: "string", editable: false, nullable: false },
"InstanceId": { type: "string", editable: false, nullable: false },
"ComponentId": { type: "string", editable: false, nullable: false },
"ScribeId": { type: "string", editable: false, nullable: false },

I have set up and configured my object store as:

 $indexedDBProvider.connection("ScribeMessagesDB").
        upgradeDatabase(1, function (event, db, tx) {
                var objStore = db.createObjectStore("ScribeMessages", {
                      keyPath: ["Environment", "SequenceId"], unique: true });
                objStore.createIndex("program_idx", "Program", { unique: false });
                objStore.createIndex("logLevel_idx", "LogLevel", { unique: false });
                objStore.createIndex("machineName_idx", "MachineName", { unique: false });
                objStore.createIndex("user_idx", "User", { unique: false });
                objStore.createIndex("environment", "Environment", { unique: false });
                objStore.createIndex("sequenceId", "SequenceId", { unique: false });
    });

I am trying to filter this way:

$indexedDB.openStore("ScribeMessages", function(store) {
                            var query = store.query();
                            store.findWhere(query.$index("environment").$eq("REN-Prod").$index("sequenceId").$gt(0).$desc(false)).then(function(limitedObjects) {
                                e.success(limitedObjects);
                            });
                        });

I should not be getting any values back, as the "Environment" column in the doesn't contain any values for "REN-Prod".

Also, how do I just query against the primary key?

thank you for your help.

marc

Failed to execute 'index' on 'IDBObjectStore': The specified index was not found.

In my code I have a function like that:

findOneByIndex: function(entityName, id, index) {
    var d = $q.defer();
    var promise = d.promise;

    $indexedDB.openStore(entityName, function(table) {
        table.findWhere(table.query().$index(index).$eq(id)).then(function(result) {
            if (result.length === 0) {
                console.log('No objects found');
                return d.reject(result);
            } else {
                return d.resolve(result[0]);
            }
        }, function(error) {
            console.log(error);
        });
    }, 'readwrite').then(null, function(error) {
        console.log(error);
    });

    return promise;
}

If I try to query IDB with an index that does not exist, I would expect the exception gets caught and logged. The problem is when I try to test this behaviour, I get:

  Uncaught NotFoundError: Failed to execute 'index' on 'IDBObjectStore': The specified index was not found.
  at angular-mocks/angular-mocks.js:9

I was wondering if it's a problem with angular mocks or with angular-indexedDB.
In my test I am injecting $indexedDB

Throw all IndexedDB errors as promises

Any code that interacts directly with the IndexedDB API needs to be wrapped in a try...catch block so that any errors can be passed to promise.reject() rather than being thrown up the stack. Currently, I have to have two types of error handling logic in my code, because some errors are thrown synchronously, and others are "thrown" asynchronously via promise.reject(). Here's an example:

var user = { id: 1, username: 'jdoe', password: 'password' };

$indexedDB.openStore('users', function(userStore) {
    try {
        userStore.upsert(user).then(
            function(result) {
                // Yay!  The IDBRequest.onsuccess event fired!
            },
            function(err) {
                // Onoes!  The IDBRequest.onerror event fired!
            }
        );
    }
    catch (e) {
        // Onoes!  IDBObjectStore.put threw an error!
    }
});

Ideally, I could get rid of the try...catch block entirely and just write the following code instead:

var user = { id: 1, username: 'jdoe', password: 'password' };

$indexedDB.openStore('users', function(userStore) {
    userStore.upsert(user).then(
        function(result) {
            // Yay!  The IDBRequest.onsuccess event fired!
        },
        function(err) {
            // Onoes!  An error occurred!  Doesn't matter whether it was IDBRequest.onerror or IDBObjectStore.put
        }
    );
});

$digest already in progress - timing problem during $apply/$digest phase?

I am currently trying to add IndexedDB support to my application as alternative to WebSQL.
During refactoring I came upon an error on some pages which appears to only happen in Firefox.

Error: [$rootScope:inprog] $digest already in progress
http://errors.angularjs.org/1.4.5/$rootScope/inprog?p0=%24digest

I've tracked down the problem to the method createDatabaseConnection where $rootScope.$apply is called.
Funny thing is that this only occurs on pages where I use ng-include with the onload attribute.
<ng-include src="'js/shared/map.html'" onload="loadMap()"></ng-include>
The onload simply calls a method in the $rootscope which does some initializing for Openlayers.

I currently don't understand why this happens or if I am doing something wrong.
One workarround I found is to delay the init method via calling setTimeout but I would be happy with something more robust and permanent.
Are the calls to $apply necessary? Or is there any way to prevent this error?

If I've got time I might try to upload an example, but I don't know if it's that easy to reproduce without the environment.

logs in code

Hi,

In he original code, console.logs were used for dev purpose. It seems that we can't disable them now.

iOS 8 bug + workaround

Hello,

The iOS 8 implementation has a bug in it. When the database is opened for the first time iOS 8 returns an absurd high version number, 9223372036854776000. This prevents the upgrade mechanism from creating the object stores and indexes. I fixed it in the generated JavaScript for our project. Could you include my fix in the CoffeeScript?

Regards, Pieter

dbReq.onupgradeneeded = function(event) {
  // Change door GINO, iOS 8 geeft initeel een enorm getal als versie in plaats van 0:
  var oldVersion = event.oldVersion;
  if (oldVersion == 9223372036854776000) {
    oldVersion = 0;
  }
  var tx;
  db = event.target.result;
  tx = event.target.transaction;
  $log.log("$indexedDB: Upgrading database '" + db.name + "' from version " + oldVersion + " to version " + event.newVersion + " ...");
  applyNeededUpgrades(oldVersion, event, db, tx, $log);
};

Extremely slow calling table.getAll() in IE (11)

The same code in IE seems to take as huge amount of time when calling getAll() as compared to Chrome.
In Chrome this code runs in <1s, in IE, it takes about minute to reach the console line. Is there something I can do to speed this up?

var loadWhiteListNodeIds = function () {
            $indexedDB.openStore('whiteListNodeIds',
              function (table) {
                  return table.find(7672990).then(function (item) {
                      table.getAll().then(function (whitelistNodeIds) {
                          console.log('setting whiteListNodeIds');
                          $scope.whitelistNodeIds = whitelistNodeIds;
                      });
                  })["catch"](function (error) {
                      return getAllWhiteListNodesAndAddToDb('whiteListNodeIds');
                  });
              });
            };

store.upsert(items) is very slow ($rootScope.$apply)

ok found that $rootScope.$apply is being called.

      notify: (args...) ->
        $rootScope.$apply =>
          @q.notify(args...)

and let's take a quick look at upsert:

      upsert: (data) ->
        @_arrayOperation data, (item) =>
          @store.put(item)

turns out that all array operations are using notify.

      _arrayOperation: (data, mapFunc) ->
        defer = @defer()
        data = [data] unless angular.isArray(data)
        for item in data
          req = mapFunc(item)
          results = []
          defer.rejectWith(req)
          req.onsuccess = (e) ->
            results.push(e.target.result)
            defer.notify(e.target.result)
            defer.resolve(results) if results.length >= data.length
        if data.length == 0
          return $q.when([])
        defer.promise

Feature: Skip and Take

Are they any query functions that can be used to support paging, like skip() and take()?

Thanks

Multiple indexedDB per app

I know its not recommended but if there is a good use case for it, what is the least detrimental way of doing it?

upgradeDatabase for $indexDB

So, for a project that dynamically adds object stores it could be useful to have a upgradeDatabase method on $indexDB. There may be a better way (docs seem rather light on examples).

/**
 @ngdoc method
 @name $indexedDB.upgradeDatabase
 @function

 @description Upgrade the database after config.
 */
upgradeDatabase: (function (this_) {
  return function (newVersion, callback) {
    return closeDatabase().then(function () {
      this_.upgradeDatabase(newVersion, callback);
      return openDatabase();
    });
  };
})(this),

A really basic idea of how this could be used is below:

$indexedDB.databaseInfo().then(function (info) {
    $indexedDB.upgradeDatabase(info.version + 1, function (event, db, tx) {
        var objStore = db.createObjectStore('newTable', { keyPath: 'id' });
        objStore.createIndex('new_idx', 'new', { unique: false });
    });
});

I've never used coffeescript, but I'm sure I could guess my way through it and do a pull request if you agree this would be useful.

insert element

In the example for inserting I see this code:
$indexedDB.openStore('people', (store) ->
store.insert({"ssn": "444-444-222-111","name": "John Doe", "age": 57}).then(function(e){...});
store.getAll().then(function(people) {
// Update scope
$scope.objects = people;
});
I don't know coffee script, but I I've been trying to mke it work in plain js, i converted it to:

$indexedDB.openStore('name', function(store){
store.insert({
'_id': shape._id,
'other': other,
'data': shape
});
});

but it doesn't work, any advice?

Small Documentation Mistake?

When installing via bower, as suggested: bower install angular-indexed-db, I get the files placed in bower_components/angular-indexedDB. Seems like the <script> tag should be

<script src="bower_components/angular-indexedDB/angular-indexed-db.js"></script>

then, no?

Feature: Add ShimIndexedDB Support

Hi Bramski
I'm using your angularjs indexeddb module for iOS support I had to fix putting the following code into
angular-indexed-db.js on line 15

indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.shimIndexedDB;

Do you think it could be possible to update your module with this fix, it will help me a lot in managing your library.

Thanks
Gaspare

Unnecessary runtime bower dependency

Is it necessary to install bower as part of the preinstall and postinstall NPM scripts?

    "preinstall": "bower >/dev/null || sudo npm install bower grunt-cli -g",
    "postinstall": "bower install"

Eliminating these would eliminate an unnecesary installation step (and invocation of sudo) for NPM users.

'IDBObjectStore': The transaction has finished.

Hi bramski,
I'm opening another issue, because I tryed to develope another way to solve the issue #11, using Restangular, I would fetch my api entity if is not stored inside indexedDB store.

$indexedDB.openStore(entityName, function(table) {
var d = $q.defer();
var promise = d.promise;

table.find(id).then(function(success) { //Change if id is used with index
    return d.resolve(success);
}, function(error) {
    Restangular.one(entityName, id).get().then(function(result) {
        table.insert(result, function(result) {
            console.log('insert ok');
        });
    });
    return d.reject(error);
});

return promise;

}, 'readwrite');

I have Error: Failed to execute 'add' on 'IDBObjectStore': The transaction has finished.

I understand the reason for async callback for restangular refers to table after the transaction is closed, is there any way to keep the transaction open and manage it inside restangular callback?

Thanks a lot for your support.

G

Very graceful source

The source is very beautiful , it's will be a popular project after the doc completed.

IE11 DataError on eachBy with no options

I got a DataError (code 0) on IE11 Edge when using the eachBy on an index but I did not pass any options. I am calling eachBy without the second parameter, like eachBy("indexName"). The problem is that when the query keyRange is set using:

                    ObjectStore.prototype.eachBy = function(indexName, options) {
                        ...
                        q = new Query();
                        ...
                        q.keyRange = keyRangeForOptions(options);
                        ...
                    };

The keyRangeForOptions function does not return anything in the case when options is not specified. This does not appear to affect Chrome or Firefox as I've been using the code for a while. However, I found that IE11 will not work with an undefined keyRange, it must be set to null. So my fix was to change:

                keyRangeForOptions = function(options) {
                    if (options.beginKey && options.endKey) {
                        return IDBKeyRange.bound(options.beginKey, options.endKey);
                    }
                };

to:

                keyRangeForOptions = function(options) {
                    if (options.beginKey && options.endKey) {
                        return IDBKeyRange.bound(options.beginKey, options.endKey);
                    } else {
                        return null;
                    }
                };

I will work on a Pull Request when I get time. I just wanted to make sure I documented it here so have a record of what the fix was.

Upgrade function ordering

upgradeDB function stores the upgrade callback functions with its version number as a key in javascript associative arrays.

But the ordering of key is not guaranteed to be preserved in javascript. (I'm not sure if the ordering is preserved in all browsers although it is not in javascript specification) so there is a possibility to apply modification to db in wrong order.

eg. create object-storeA in version1 and delete object-storeA in version2. (these should not be applied in reverse order)

store.find not working as expected

Hello, how are you doing?

I started using angular-indexedDB today, but I'm having dificulties working with the store.find() function.

You see, I'm defining a store like this:

db.createObjectStore('campaigns', {keyPath: 'id', autoIncrement: true});

... and I'm able to have insert() and getAll() work as I expected. But, when I try to use the store.find(), like this:

store.find($state.params.campaign_id).then(function(campaign) {
  $scope.campaign = campaign;
});

... it simply, doesn't works.

I already have certified (through simple debugging with console.log) that the $state.params are well-formed, and correct, also that there's an entry which possesses a property id equal to the parameter, when the function is called.

Could it be that the store.find() function does not behaves properly when the store have a keyPath and a keyGenerator (autoIncrement) ?

--UPDATE 09/08/2015--

Greetings.

I was able to make it work as I wanted, but I had to pass the entire campaign object through the params, instead of only the id:

store.find($state.params.campaign.id).then(function(campaign) {
  $scope.campaign = campaign;

It seems the store.find() function does not performs a deep comparison between the store.key and the value passed as argument, what would explain why passing a by-copy value (instead of the actual reference) does not works.

Also I'm not sure if the store.find() function's key comparison takes data type (primitives, like String, Number, etc) into account.

Adds then retrieves first time. Can't retrieve second time

Kindly see this snippet in the README:
`angular.module('myModuleName')
.controller('myControllerName', function($scope, $indexedDB) {

$scope.objects = [];

$indexedDB.openStore('people', function(store){

  store.insert({"ssn": "444-444-222-111","name": "John Doe", "age": 57}).then(function(e){...});

  store.getAll().then(function(people) {  
    // Update scope
    $scope.objects = people;
  });
});

});`

The store.getAll() should probably come out of that indexedDB.openStore(....) { ... } block.

When I tried the above snippet, the objects are added on first time, if the db doesn't exist, but subsequent ones, no retrieval happens

I did this and it works fine:

$indexedDB.openStore('myStop', function(store) {
            store.getAll().then(function(data) {
                // Update scope
                $scope.objects = data;
            });
        });

Additional Maintainers Needed

The project for which this project was written is going EOL and that means that this is highly unlikely to see any active use from me for a very long time. I would be quite happy to keep the project hosted under my username but to add a collaborator to the repo as this codebase is rapidly fading from my memory.

InvalidAccessError on IE 11

Hi

Using the newest IE 11 (as of today) on Windows 11 pro, I encountered the following wired InvalidAccessError:

invalidaccesserror-ie11

Which happens on this line.

The root cause of this is because MS IndexedDB implementation (for whatever reason not clear to me) expects a fix number literal as a second argument and refuses to evaluate any expression like dbVersion || 1 or dbVersion etc. The same line works like a charm using Chrome Version 42.0.2311.135 m on Windows.

My current workaround is:

dbReq = indexedDB.open(dbName, 1);

Which of course is not a real fix to this issue!

Using with an Angular Cordova App?

Hi Guys!
I tried tu use this library with a Cordova mobile app with Angular but the commands are never executed.
Has anyone used this with Cordova?
Thanks!

as fou multiple conditions

    $indexedDBProvider
    .connection('myIndexedDB11')
    .upgradeDatabase(1, function(event, db, tx) {
        var objStore = db.createObjectStore('5173', {
            keyPath: "id",
            autoIncrement: true
        });
        objStore.createIndex('i3n_idx', ['hero','skin','price'], {
            unique: false
        });
    });

$indexedDB.openStore('5173', function(store) {
        var find = store.query();
        //  $between(lower, upper, doNotIncludeLowerBound? true/false, doNotIncludeUpperBound true/false) - between two bounds 
        find.$between(
            [$scope.vm.Hmin, $scope.vm.Smin, $scope.vm.Pmin], [$scope.vm.Hmax, $scope.vm.Smax, $scope.vm.Pmax], true, true
        );
        find.$index("i3n_idx");
        store.eachWhere(find).then(function(accounts) {
            $scope.vm.result = accounts; 
        });
    });

It looks like it just looking at the first condition( Hmin,Hmax ), ignoring the other conditions [(Smin,Smax)...].

Feature: Create stores dynamically

In my case, I have to add stores when needed. But looks like this implementation offers to create stores during config phase. Can you please guide me to create multiple stores dynamically.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.