How to delete Backbone model from localStorage collection - backbone.js

I have created some models all saved in local storage collection. My challenge is how to delete a model fom the collection in local storage using one of the model attributes value. Below is extract of my code:
var Food = Backbone.Model.extend({
defaults: {
title: '',
calories: 0,
date: '',
history: false
}
});
var Foods = Backbone.Collection.extend({
model: Food,
localStorage: new Backbone.LocalStorage('Health-Tracker')
});
my_foods = new Foods({});
var ls = new Backbone.LocalStorage('Health-Tracker');
var res = ls.findAll();
var n = res.length;
var i, id;
for (i = 0; i < n; i++) {
food = res[i];
id = food['id'];
title = food['title'];
calories = food['calories'];
date = food['date'];
history = food['history'];
//I am stuck here
if (history) {
ls.remove(food); // Not working
// I have also tried this
ls.remove(id); // not working
}
}
Note that history is set to true successfully for some models in other section of the bigger codes. Above is only where I need to take action if history value is true. And it is bad code for now.
Any assistance is appreciated

Note that this app does not use server to store/retrieve data. All models are stored in the local storage. It is a very long process to use findAll() and remove() as I used above to delete from the localstorage. The following was added to delete models from the local storage:
my_foods.fetch();
my_foods.models.forEach(function(food){
day = food.get('day');
new_day = get_new_day();// this function isn't included above
if (new_day > day) {
food.destroy();
}
});

Related

Nedb non-unique _id indexing

I have a Nedb database for my electron.js app that generates _id replicas even with ensureIndex({… unique: true}). Onclick, an indexed value is to increment by 5 - instead a new index is generated with said value. Example:
// Before click
{"_id":0,"testVal":0}
{"_id":1,"testVal":0}
{"_id":2,"testVal":0}
…
// After click
{"_id":0,"testVal":0} // Intended: {"_id":0, "testVal":5}
{"_id":1,"testVal":0}
{"_id":2,"testVal":0}
…
{"_id":0,"testVal":5}
Relevant code:
var Datastore = require('nedb');
db = new Datastore ({filename: 'db/rtest.db', autoload: true});
// Database functions
exports.createTestVal = function(i, passVal) {
var test = {_id: i, testVal: passVal};
db.insert(test, function(err, newDoc){})};
exports.updateTestVal = function(i, passVal) {
db.update({_id: i}, {$set: {"testVal": passVal}}, {}, function(err, numReplaced){});}
exports.getTestVal = function(fnc){
db.find({}, function(err, docs) {fnc(docs)})}
exports.deleteTestVal = function(id) {
db.remove({_id: id}, {}, function(err, numRemoved){})}
// Event functions
const database = require('../assets/js/testdatabase'); // 'testdatabase' = code above
var btnTst = document.getElementById('add5'); var i = 0;
db.ensureIndex({ fieldName: "_id", unique: true }, function (err) {});
btnTst.addEventListener('click', function(event){
var value = Number(this.value);
database.updateTestVal(i, value);
i++;})
window.addEventListener('load', function() {
database.getTestVal(function(testVals) {
for (k = 0; k < 10; k++) {if (testVals.length == k){fillValues(k)}}})})
function fillValues(k){for (p = k; p < 10; p++){database.createTestVal(p, 0)}}
<button id="add5" value=5>+5</button>
Tried modifying variable types, reordering functions, among others - to no avail. The GitHub documentation claims that _id is uniquely-indexed by default, but isn't so in my use.
Any workarounds?
Assuming that you are seeing these "duplicates" while viewing the physical file that your database is being written to, everything is working as expected.
From the NeDB documentation:
Persistence
Under the hood, NeDB's persistence uses an append-only format, meaning that all updates and deletes actually result in lines added at the end of the datafile, for performance reasons. The database is automatically compacted (i.e. put back in the one-line-per-document format) every time you load each database within your application.

Loading array of display objects using shared objects in action script 3.0

I'm trying to load an array that contain some display objects, the program lets me to populate the array with circles and save them to a shared object, then, I can trace the content of my array using the load button. The problem is that i can't load the array after that I restart my program. It traces me this message:"objects loaded: ,,,"
This is the code:
var SO:SharedObject=SharedObject.getLocal("myFile", "/");
var arr:Array=new Array();
var counter:Number=-1;
addBtn.addEventListener(MouseEvent.CLICK, addObjects);
saveBtn.addEventListener(MouseEvent.CLICK, saveObjects);
loadBtn.addEventListener(MouseEvent.CLICK, loadObjects);
function addObjects(event:Event) {
counter++;
var circle:circleClip=new circleClip();
arr.push(circle);
trace("current object: "+arr[counter]);
}
function saveObjects(event:Event) {
SO.data.arrSaved=arr;
SO.flush();
trace("objects saved: "+SO.data.arrSaved);
}
function loadObjects(event:Event) {
var arrLoaded:Array=new Array();
arrLoaded=SO.data.arrSaved;
trace("objects loaded: "+arrLoaded);
}
You are to understand MVC pattern approach: https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
You need to separate data from the code that visualizes things out of these data, and store data only. Something like:
// Lets say this Array contains a list of your circle objects.
var Curcus:Array;
// Storage.
var SO:SharedObject = SharedObject.getLocal("myFile", "/");
function saveCircus():void
{
var aList:Array = new Array;
aList.length = Circus.length;
for (var i:int = 0; i < Curcus.length; i++)
{
// Get an object.
var aCircle:Sprite = Curcus[i];
// Record its properties you want to store.
var anEntry:Object =
{
"x":aCircle.x,
"y":aCircle.y,
"scaleX":aCircle.scaleX,
"scaleY":aCircle.scaleY
};
// Store the entry.
aList[i] = anEntry;
}
// Store and save data.
SO.data.arrSaved = aList;
SO.flush();
}
function loadCircus():void
{
// Retrieve saved data.
var aList:Array = SO.data.arrSaved;
// Make it empty data if there are none.
if (!aList) aList = new Array;
Circus = new Array;
Curcus.length = aList.length;
for (var i:int = 0; i < aList.length; i++)
{
// Get one entry.
var anEntry:Object = aList[i];
// Create a new item. BTW, naming classes with the
// lowercase first letter is the 8th cardinal sin.
var aCircle = new CircleClip;
// Restore saved properties.
aCircle.x = anEntry['x'];
aCircle.y = anEntry['y'];
aCircle.scaleX = anEntry['scaleX'];
aCircle.scaleY = anEntry['scaleY'];
// Add to display list.
addChild(aCircle);
// Keep it for the future reference/saving.
Curcus[i] = aCircle;
}
}

Backbone fetch (or sync) doesn't look up right url

I'm trying to get some data from the node server, which works fine, but when I try to GET data via the Backbone fetch (or sync), the request fails. I noticed that, for some reason, actual request is wrong: 'GET http://localhost:3000/socket.io/1/' where it should be 'GET http://localhost:3000/cars', since '/cars' is the value of the URL field that Backbone uses by convention for these operations. These are the relevant modules:
var Backbone = require("backbone");
var Car = require('models/car');
var Cars = Backbone.Collection.extend ({
model: Car,
url: '/cars',
// Unselect all Car Cards
resetSelected: function() {
for (var i=1; i<=this.length; ++i) {
var carcard=this.get(i);
carcard.set({"selected": false});
console.log(carcard.attributes.name + ' unselected');
}
},
// Select a specific model from the collection
selectByID: function(id) {
this.resetSelected();
var carcard = this.get(id);
carcard.set({"selected": true});
console.log(carcard.attributes.name + " selected");
return carcard.attributes.id;
}
});
module.exports = Cars;
And a model:
var Backbone = require("backbone");
var Car = Backbone.Model.extend({
defaults: {
year: 2011,
brand: "Brand",
model: "Model",
name: "Car Name",
pictureFle: "img/car.jpg",
kmTraveled: 0,
litresSpent: 0,
selected: false
},
});
module.exports = Car;
I tried to populate the collection like this:
var cars = new Cars();
cars.fetch();
but, as I explained, failed. Any ideas what the problem could be?

IndexedDB key generator resets after put-transaction

This problem has me stumped.
For some reason, the autoincrementing key generator in indexedDB resets after performing and update on an existing object with a put-transaction, leading to overwrites of data in the database.
For my app, I'm using a self written IndexedDB service for angularJS with all the basic CRUD functions implemented.
I may also add that I'm developing with Ionic Framework, even though I doubt that is to blame.
Considering the service is a work-in-progress, I've let the key path for an object store default to "id" with an autoincrementing strategy.
The indices for the given store, nevertheless, are up to the user to decide in a specific object.
As an example:
dbHelper.objectStores = [{'employees',
indices: [{indexName: 'name', isUnique: false},
{indexName: 'phone', isUnique: true}]}];
This would, unless already created in the db, create the object store 'employees' with indices 'name' and 'phone', where 'phone' would have to be a unique value while 'name' would not.
Here is the implementation of the openDB function.
Please note that dbHelper.objectStores is supposed to be empty as it's up to the user to assign these properties before opening the db(or else it is defaulted).
angular.module('dbProvider', [])
.factory('$db', ['$window', function($window) {
// DB Object
var dbHelper = {};
// Properties - Are given defaults unless assigned manually by user before openDB is invoked.
dbHelper.dbName = 'defaultDB';
dbHelper.dbVersion = 1;
dbHelper.objectStores = [];
dbHelper.openDB = function(onCompleteCallback, onErrorCallback) {
console.log('Atempting to open db with name ' + dbHelper.dbName + '.');
var request = $window.indexedDB.open(dbHelper.dbName, dbHelper.dbVersion);
// Invoked by indexedDB if version changes
request.onupgradeneeded = function(e) {
console.log('Version change. Current version: ' + dbHelper.dbVersion);
var db = e.target.result;
e.target.transaction.onerror = onErrorCallback;
if(dbHelper.objectStores.length === 0) {
dbHelper.objectStores.push({name:'defaultStore', indices: []});
}
for(var store in dbHelper.objectStores) {
if(db.objectStoreNames.contains(dbHelper.objectStores[store].name)) {
console.log(dbHelper.objectStores[store].name + ' deleted.');
db.deleteObjectStore(dbHelper.objectStores[store].name);
}
var newStore = db.createObjectStore(dbHelper.objectStores[store].name, {keyPath: "id", autoIncrement: true});
for(var index in dbHelper.objectStores[store].indices) {
newStore.createIndex(dbHelper.objectStores[store].indices[index].indexName,
dbHelper.objectStores[store].indices[index].indexName,
{unique : dbHelper.objectStores[store].indices[index].isUnique});
}
console.log(dbHelper.objectStores[store].name + ' created.');
}
};
request.onsuccess = function(e) {
console.log('DB ' + dbHelper.dbName + ' open.');
dbHelper.indexedDB.db = e.target.result;
onCompleteCallback();
};
request.onerror = onErrorCallback;
};
Here are some of the CRUD functions(the ones in question):
dbHelper.findItemWithIndex = function(keyValue, storename,
onCompleteCallback,onErrorCallback) {
var db = dbHelper.indexedDB.db;
var trans = db.transaction([storename], "readwrite");
var store = trans.objectStore(storename);
var index = store.index(keyValue.key);
index.get(keyValue.value).onsuccess = function(event) {
onCompleteCallback(event.target.result);
};
};
dbHelper.addItemToStore = function(item, storename,
onCompleteCallback, onErrorCallback) {
var db = dbHelper.indexedDB.db;
var trans = db.transaction([storename], "readwrite");
var store = trans.objectStore(storename);
var request = store.add(item);
trans.oncomplete = onCompleteCallback;
request.onerror = onErrorCallback;
};
dbHelper.deleteItemFromStore = function(itemId, storename,
onCompleteCallback, onErrorCallback) {
var db = dbHelper.indexedDB.db;
var trans = db.transaction([storename], "readwrite");
var store = trans.objectStore(storename);
var request = store.delete(itemId);
trans.oncomplete = onCompleteCallback;
request.onerror = onErrorCallback;
};
dbHelper.updateItem = function(item, storename, onCompleteCallback, onErrorCallback) {
var db = dbHelper.indexedDB.db;
var trans = db.transaction([storename], "readwrite");
var store = trans.objectStore(storename);
var request = store.put(item);
trans.oncomplete = onCompleteCallback;
request.onerror = onErrorCallback;
};
Finally, the code from the controller where the transactions are invoked.
The strategy here, is that the item is added to the db using the addItemToStore function the first time it is persisted, and then afterwards the updateItem function.
After adding the first time, the object is immediately fetched in order to keep working on it with the assigned id from the db.
$scope.updateTemplate = function() {
console.log('Saving..');
var onCompleteCallback = {};
if(!$scope.formTemplate.firstSave) {
onCompleteCallback = $scope.updateModel;
} else {
$scope.formTemplate.firstSave = false;
onCompleteCallback = $scope.setId;
}
$db.updateItem($scope.formTemplate, $scope.objectStore.name,
onCompleteCallback, $scope.dbError);
};
$scope.newItem = function() {
$db.addItemToStore($scope.formTemplate, $scope.objectStore.name,
$scope.setId, $scope.dbError);
};
$scope.setId = function() {
$db.findItemWithIndex(
{key: 'title',
value: $scope.formTemplate.title},
$scope.objectStore.name,
function(result) {
console.log(JSON.stringify(result));
$scope.formTemplate = result;
},
function(error) {
$scope.dbError(error);
});
}
It's here everything goes to hell.
I add an object, go back to another view and find it in the list with id=1.
I add another object, go back to the list view, and there it is with id=2.
And so forth and so forth..
Then, after updating either of the objects with the $scope.updateTemplate function, which also works like a charm, things get interesting:
The next object added gets id=1 and totally erases good old numero uno from earlier.
The next objects also get id's that cause them to replace the already existing objects.
What could cause this?
For testing I'm using Safari 8 in OS 10.10 and I'm deploying to an LGG2 with KitKat 4.4.2.
To be honest, I skimmed, but I saw this, "Safari 8" - the latest iOS and Safari have serious bugs with IndexedDB: http://www.raymondcamden.com/2014/9/25/IndexedDB-on-iOS-8--Broken-Bad
In iOS9, many of the IndexedDb bugs are fixed, but not all. We are currently testing on iOS9 Beta 2 and this particular bug that you found is not fixed.
We were able to work around this problem by not using autoincrement on our object stores. We just manually find the max key value and increment that.
Inserting an object looks something like this:
var store = db.transaction([entity], "readwrite").objectStore(entity);
store.openCursor(null, "prev").onsuccess = function (event) {
var maxKey = event.target.result.key || 0;
object.id = maxKey + 1;
store.add(object);
}

Sencha Touch 2 store get record

I have a problem.
I have 2 store files (1 event and 1 places). I'm loading these stores from a database. Now the problem is that in the event store there is a field called {id_place}. This field contains a number which is also a number in the places store. Now what I need to do is get the name from the place of the {id_place}. So the {name} is a field in the places store. So what I need is a function to get a record from another store and then get the {name} from that store. So I send the id_place to the placestore, then I need to find the record with that id and I need to get the field {name} from that record. I don't know if I'm making sense, it's kinda hard to explain. I hope this can be done.
Thanks in advance!
Edit:
showPlace: function(id_place){
var placeUrl = 'http://admin.hishanghai.info/sencha/places.php?action=read&callback=callback&id=' + id_place;
store = new Ext.data.Store({
model: 'android.model.Placesmodel',
autoLoad: true,
proxy: {
type: 'scripttag',
url: placeUrl,
reader: {
type: 'json',
rootProperty: 'place'
},
extraParams: {
action: 'read'
}
}
})
//var naam = Ext.getStore('Placesstore').getById('id_place').get('name')
//var Record = store.getAt(id_place);
//var naam = store.getById('id_place').get('name');
var naam = store.get('name');
return naam;
}
This code creates a store with the info from 1 record. Now I only need to access the name field. how do i do that?
found it:
showPlace: function(id_place){
var placesstore = Ext.getStore('Placesstore');
var i =0;
var placeid = 0;
var aRecord;
while(placeid != id_place){
aRecord = placesstore.getAt(i);
placeid = aRecord.data.id;
i+=1;
}
var naam = aRecord.data.name;
return naam;
}

Resources