Wondering if anyone has a working pattern for autosave or periodic saves with ember-data without blocking the user. Something like Google Docs.
The main issue I’m encountering is when a record is committed, its inflight status means changes from bound controls throw exceptions. So you can’t just trigger a commit every few minutes or on text field blur, cause if the user continues typing, it all blows up.
You could store the text the user is typing in a different property than the attribute you’re planning to save, for example on the view. This way you can copy it when you save, but there won’t be any conflict as the user is typing, because he’s just modifying the buffer, and not the actual record.
A similar issue with this is when you try to reload records via websocket, and suddenly one of them is being edited by the user, which ends up in error as well
I was trying to create a BridgeAdapter to better facilitate such scenarios, where the local storage adapter acts as the local “buffer” (cache), and then synchronizes with the server using REST adapter. Would be awesome when we have a working solution for this I think Also to allow the server to push model updates to clients (fx via web sockets) and having the clients update their local cache only.
Slightly unrelated and not Ember-specific, but if you are trying to handle merging concurrent updates, you might want to look at something like Operational transformation - Wikipedia for how to resolve these things.
I’m sure I missed some important point here. I feel like this means that someone needs to stop using bindings whenever using autosave then implement the “binding” work without ember. Looks like a lot of work and not really DRY.
I’ve just implemented this for our app with Ember Data.
Basically, I override setUnknownProperty on my ObjectController and schedule a save to occur using a debounce function. Also, I have to coalesce the property changes until the model is resolved, otherwise I get a complaint about the model not being able to handle the event “willSetProperty” while it’s inFlight. When I have some more time, I could write up a more detailed post.
I will try your approach. I’m very interested in your detailed post. Especially the part about coalescing property changes to avoid inFlight. The debounce function seems easy to implement. I hope you will find the time to post it.
The debounce function should be removed as soon as backburner supports proper debouncing (see https://github.com/ebryn/backburner.js/pull/31). As for the logic behind this, I wanted to override set on an ObjectController and prevent properties from getting set while a record was in flight. But Ember uses Ember.set a lot of places in the core code, so I had to settle with setUnknownProperty, which ends up working just fine (but has some caveats associated with it). The reasoning behind coalescing properties is that I would frequently get errors from Ember Data stating that records in flight couldn’t handle the willSetProperty event. The recursion is there to ensure that we set the properties in bulk on the model when it has been finally resolved on the client. And to prevent spammy saving, it debounces calls to save for a configurable amount of time so it saves in a predictable and frequent fashion.
As for using the mixin, all you have to do is include it in your ObjectController (if it’s a vanilla pass-through controller):