Modifying the Backbone.localStorage adapter to accomodate special characters(eg: commas) in it's keys
Backbone.localStorage is for the most part, working without any problems.
It allows the user to assign a name to the storage instance, stores the model ids in the localStorage as a comma seperated string with the name as the key.
If the models don't have any ids they're awarded one by the adapter itself. Such ids take the format of a GUID.
The problem arises when one of the model ids contain a comma.
Say, you had a bunch of models.
let a = new Model({ id: 'comma, seperated' });
let b = new Model({ id: 'not_comma_seperated ' });
When they're added to the Collection with the adapter attached to it, the adapter adds it to the records array and save it after calling [].join()
with a comma as it's seperator.
The localStorage would then somewhat resemble this:
localStorage = {
"COLLECTION_NAME" : "comma, seperated,not_comma_seperated",
"COLLECTION_NAME-comma, seperated": { id: "comma_seperated" },
"COLLECTION_NAME-not_comma_seperated": {id: "not_comma_seperated"}
}
Now, when the page reloads, and the ids are retrieved and split the adapter would assume that "comma "
and " seperated"
are two seperate models and attempt to find them both to no avail.
A simple solution is to serialize the ids as a JSON object. But seeing as how the repository is unmaintained, I don't see that happening any time soon.
We can modify the Backbone.LocalStorage
's instance methods to suit our needs.
// This method should be called before any fetch calls so that the correct
// ids are retrieved.
Backbone.LocalStorage.prototype.read = function(){
this.records = JSON.parse(localStorage.getItem(this.name)) || [];
};
// We're overwriting the save method to serialize the ids before saving them.
Backbone.LocalStorage.prototype.save = function(){
localStorage.setItem(this.name, JSON.stringify(this.records));
};
But seeing as how the records are being read and split in the constructor itself, you can't just overwrite it. So the workaround involves overwriting the fetch method for the Collection itself to call the newly added read
method.
var Collection = Backbone.Collection.extend({
...
localStorage: new Backbone.LocalStorage('name-here'),
fetch: function(){
this.localStorage.read();
return Backbone.Collection.fetch.call(this, arguments);
},
...
})