Skip to content

Instantly share code, notes, and snippets.

@menixator
Last active September 28, 2016 11:43
Show Gist options
  • Save menixator/c600674c67cd2a458148c1585a4c863a to your computer and use it in GitHub Desktop.
Save menixator/c600674c67cd2a458148c1585a4c863a to your computer and use it in GitHub Desktop.
Modifying the Backbone.localStorage adapter to accomodate special characters(eg: commas) in it's keys

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.

Fix

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.

Workaround

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);
  },
  ...
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment