5

just a very short question on using Backbone.js with LocalStorage:

I'm storing a list of things (Backbone collection) in LocalStorage. When my website is open in multiple browser windows / tabs and the user in both windows adds something to the list, one window's changes will overwrite the changes made in the other window.

If you want to try for yourself, just use the example Backbone.js Todo app:

  1. Open http://backbonejs.org/examples/todos/index.html in two browser tabs
  2. Add an item 'item1' in the first tab and 'item2' in the second tab
  3. Refresh both tabs: 'item1' will disappear and you'll be left with 'item2' only

Any suggestions how to prevent this from happening, any standard way to deal with this?

Thxx

user1151506
  • 55
  • 1
  • 5

3 Answers3

4

The issue is well-known concurrency lost updates problem, see Lost update in Concurrency control?. Just for your understanding I might propose the following quick and dirty fix, file backbone-localstorage.js, Store.prototype.save:

save: function() {
    // reread data right before writing
    var store = localStorage.getItem(this.name);
    var data = (store && JSON.parse(store)) || {};
    // we may choose what is overwritten with what here
    _.extend(this.data, data);

    localStorage.setItem(this.name, JSON.stringify(this.data));
}

For the latest Github version of Backbone localStorage, I think this should look like this:

save: function() {
  var store = this.localStorage().getItem(this.name);
  var records = (store && store.split(",")) || [];
  var all = _.union(records, this.records);
  this.localStorage().setItem(this.name, all.join(","));
}
Community
  • 1
  • 1
Yaroslav
  • 4,543
  • 5
  • 26
  • 36
2

You may want to use sessionStorage instead. See http://en.wikipedia.org/wiki/Web_storage#Local_and_session_storage.

Yaroslav
  • 4,543
  • 5
  • 26
  • 36
  • This is the correct answer. There's only a local-storage adapter for backbone.js , http://backbonejs.org/docs/backbone-localstorage.html you will have to write your own implementation to use session-storage – Ahmad Alfy Jun 07 '12 at 10:36
  • Sorry, I should have been more clear. What I want is **localStorage**, as I need the data to be persisted between sessions. Just take the above Todo list as an example: You don't want your todo list to be cleared when you close the tab or browser window. The next time you come back to your app, you want it to be there. – user1151506 Jun 07 '12 at 11:15
  • Imagine you opened two windows, filled different data in, closed both, opened a new one. Which of the two previously closed it should take data from? You need full-fledged authorization and authentication then. – Yaroslav Jun 07 '12 at 11:35
  • 1
    No, I don't want to identify or authenticate any users. It's a much simple case. Again, the Todo app as an example: Imagine you have it open in two browser tabs. If you add todo items in both tabs, you don't want the data of either the first or the second tab. Obviously you want both. If you add a todo item in both tabs, you want BOTH items to be stored in local storage, not the later added item overwriting the first one. – user1151506 Jun 07 '12 at 13:02
2

Yaroslav's comment about checking for changes before persisting new ones is one solution but my suggestion would be different. Remember that localStorage is capable of firing events when it performs actions that change the data it holds. Bind to those events and have each tab listen for those changes and view re-render after it happens.

Then, when I make deletions or additions in one tab and move over to the next, it will get an event and change to reflect what happened in the other tab. There won't be weird discrepancies in what I'm seeing tab to tab.

You will want to give some thought to making sure that I don't lose something I was in the middle of adding (say I start typing a new entry for my to-do list), switch to another tab and delete something, and then come back I want to see the entry disappear but my partially typed new item should still be available for me.

John Munsch
  • 19,530
  • 8
  • 42
  • 72
  • This solution has better user experience. – Yaroslav Jun 07 '12 at 16:57
  • This solution seems formally more correct and would be less of hack, true! But it comes with a lot of quirks or lack of support in IE, Safari and Chrome. Just tried it and it works well in FF but not really in Chrome, which is why I went with the hack mentioned above. – user1151506 Jun 07 '12 at 22:37