Reputation: 5611
tl;dr: Is editing a model's attributes while the model is saving officially unsupported? I seem to recall that attempts to edit while a record was inFlight used to be rejected by the state machine circa 2013, but I thought that limitation had been removed. It no longer throws a state-machine error...it just seems to cause errors later :/
In the app I'm working on, hitting enter creates a new entry and focuses the title field, letting the user immediately start typing. The changes to that field are automatically persisted with a debounced save. Generally this works well, but if I start typing too quickly, I'm getting the following error:
Attempted to handle event `didCommit` on <app@model: ...> while in state root.loaded.updated.uncommitted.
(I've included the full error & traceback at the bottom [1])
The record does appear to be properly persisted to the server (Firebase through the EmberFire adapter), but there is other weirdness with the app from that point on (presumably because that iteration of the run loop blows up before completing).
To see what's up, I've attached observers onto the model's currentState.stateName
and title
fields. For a create-and-save without error, the record passes through the following states:
[Press Enter; Pause]
|
V
root.loaded.created.uncommitted
|
V
<title observer fires with blank>
|
V
root.loaded.created.inFlight
|
V
root.loaded.saved
|
V
[Type in title]
|
V
root.loaded.updated.uncommitted
|
V
<title observer fires with value>
|
V
root.loaded.updated.inFlight
|
V
root.loaded.saved
When the error appears, the process looks like this:
[Press Enter & type immediately]
|
V
root.loaded.created.uncommitted
|
V
<title observer fires with blank>
|
V
root.loaded.created.inFlight
|
V
[title observer fires with value]
|
V
root.loaded.saved
|
V
root.loaded.updated.uncommitted
|
V
<Error appears>
|
V
root.loaded.updated.inFlight
|
V
root.loaded.saved
My initial thought was that the error was being caused by the second save starting before the initial creation is complete, but the error happens in root.loaded.updated.uncommitted
-- before the record enters root.loaded.updated.inFlight
. I'm pretty sure this means the problem is caused by the actual editing of the field, not the call to save()
the record.
Edit: Indeed, completely removing the saving of the title doesn't appear to have any effect. That seems to indicate the problem really does stem just from editing the field.
Looking at the traceback (below), it isn't obvious what is causing the didCommit
event. I was wondering if my problem is the fault of EmberFire for calling didSaveRecord()
while the model is in the wrong state, but searching the EmberFire codebase doesn't turn up any calls to didSaveRecord()
whatsoever so that doesn't appear to be the issue.
Is this just the as-designed behavior of Ember Data? If so, it seems like a pretty serious limitation that I haven't seen mentioned anywhere.[2]
At one point, ED used to prevent setting properties while a record was inflight, but I thought that limitation had been removed (and it isn't explicitly preventing me from doing so like it used to).
The first workaround that comes to mind is to buffer writes to the field until the model is in a "writable" state...except I've never seen any of the official Ember examples do that.
Is that the correct (or at least a reasonable) solution?
If so, what constitutes a "writable" state? Anything other than inFlight
? (which I can just check for with the isSaving
flag, right?)
And if not, is there another officially-recommended pattern to deal with this?
Edit:
In reading through an old thread about autosave I came across an article that mentions a Buffered Proxy pattern (last main section: "Give Our Attributes a Buffer") that sounds pretty similar to what I'm describing. That links to sample code by Luke Melia from 2013 that Stefan Penner said they used "regularly" (at that time). Both of those two are active contributors to the Ember community, so I'd take taht as effectively "official" advice, but the question remains: is this still the suggested approach three years later?
Edit:
That proxy pattern is now packaged as the ember-buffered-proxy Ember CLI addon, but it's README still doesn't really mention when this pattern might be needed (which seems to imply it's something occasionally useful in particular scenarios needing that functionality, not as a fix for a core limitation of Ember Data)
[1] Full error/traceback:
ember.debug.js:31352 Error: Attempted to handle event `didCommit` on <app@model:task::ember965:-KLmwiGUhqrUW_CiRGb4> while in state root.loaded.updated.uncommitted.
at new Error (native)
at Error.EmberError (http://app.localtest.me:4200/assets/vendor.js:25781:21)
at InternalModel._unhandledEvent (http://app.localtest.me:4200/assets/vendor.js:82039:13)
at InternalModel.send (http://app.localtest.me:4200/assets/vendor.js:81917:14)
at InternalModel.adapterDidCommit (http://app.localtest.me:4200/assets/vendor.js:82220:12)
at didSaveRecord (http://app.localtest.me:4200/assets/vendor.js:89092:21)
at http://app.localtest.me:4200/assets/vendor.js:89814:15
at Object.Backburner.run (http://app.localtest.me:4200/assets/vendor.js:10788:25)
at _adapterRun (http://app.localtest.me:4200/assets/vendor.js:89648:31)
at http://app.localtest.me:4200/assets/vendor.js:89805:13
onerrorDefault @ ember.debug.js:31352
exports.default.trigger @ ember.debug.js:52095
(anonymous function) @ ember.debug.js:53346
Queue.invoke @ ember.debug.js:333
Queue.flush @ ember.debug.js:397
DeferredActionQueues.flush @ ember.debug.js:205
Backburner.end @ ember.debug.js:560
(anonymous function) @ ember.debug.js:1126
[2] The only two three four mentions of similar issues that I've come across are:
isSaving
property). And, as I said earlier, even getting rid of the post-title-change autosave altogether doesn't seem to have an effect.DS.Transform
's serialize()
methodRoute
's model()
hook, where it is simple to wait for the save to complete before continuing.inFlight
causing an invalid state transition. First, this doesn't cause the same error anymore. Second, the only solution provided was to switch to Ember Persistence Foundation, which appears to have been abandoned in mid 2014 (Edit: confirmed)Upvotes: 6
Views: 1235